plone.app.testing can't call BrowserView
plone, python, testing
Solution
Browser views are nothing but named multi adapters; to test them you have call them on the right context and to manually set up the request to provide the interface declared for the view; in you case is probably something like this:
from zope.interface import alsoProvides
from Products.MyProduct.browser.promoboardhome import IPromoBoardHome
class TestPromoBoardHome(unittest.TestCase):
layer = PROD_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
self.request = self.layer['request']
alsoProvides(self.request, IPromoBoardHome)
I have a bunch of browser views tests on packages like collective.nitf.
Happy testing!
Problem
I've added a couple of BrowserViews through paster, now I'm trying to run them from plone.app.testing, because I like repeatable and consistent tests. Calling the view manually from the browser works without any problems. I've tried both importing and initializing views manually, as well as calling the class from restricted traverse. In both cases an object gets initialized just fine but when I try to trigger rendering either calling the instance as a function or using __call__() method, I get the following error: ``` *** KeyError: 'global_cache_settings ``` I looked at the example in README.rst in plone.app.testing it doesn't seem to mention the problem, quick googling didn't yield any results either. It could be one of the site customization, however when greping the source, I found 'global_cache_settings' mentioned in Products.CMFPlone, so it's probably a plone thing: ``` eggs/Products.CMFPlone-4.1.4-py2.6.egg/Products/CMFPlone/skins/plone_templates/main_template.pt 28: <metal:cache use-macro="context/global_cache_settings/macros/cacheheaders"> 29: Get the global cache headers located in global_cache_settings. eggs/plone.app.layout-2.1.13-py2.6.egg/plone/app/layout/presentation/presentation.pt 11: <metal:cache use-macro="here/global_cache_settings/macros/cacheheaders"> 12: Get the global cache headers located in global_cache_settings. eggs/plonetheme.sunburst-1.1.6-py2.6.egg/plonetheme/sunburst/skins/sunburst_templates/main_template.pt 20: <metal:cache use-macro="context/global_cache_settings/macros/cacheheaders"> 21: Get the global cache headers located in global_cache_settings. ``` Here's relevant class declarations: ``` from zope.interface import implements, Interface from Products.Five import BrowserView from Products.CMFCore.utils import getToolByName from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile from Products.MyProduct import MyProductMessageFactory as _ class IPromoBoardHome(Interface): """ PromoBoardHome view interface """ def __init__(self, context, request): pass def __call__(self): pass def test(): """ test method""" class PromoBoardHome(BrowserView): """ PromoBoardHome browser view """ implements(IPromoBoardHome) def __init__(self, context, request): self.context = context self.request = request def __call__(self): return ViewPageTemplateFile('pt/promoboardhome.pt')(self) @property def portal_catalog(self): return getToolByName(self.context, 'portal_catalog') @property def portal(self): return getToolByName(self.context, 'portal_url').getPortalObject() def test(self): """ test method """ dummy = _(u'a dummy string') return {'dummy': dummy} ``` Template: ``` <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" metal:use-macro="here/main_template/macros/master" i18n:domain="Products.MyProduct"> <body> <div metal:fill-slot="main"> <tal:main-macro metal:define-macro="main" tal:define="testview view/test"> <span tal:content="testview/dummy">test</span> </tal:main-macro> </div> </body> </html> ``` configure.zcml declaration: ``` <browser:page for="*" name="promoboardhome" class=".promoboardhome.PromoBoardHome" allowed_interface=".promoboardhome.IPromoBoardHome" permission="zope2.View" /> ``` test file: ``` import unittest2 as unittest from . import PROD_INTEGRATION_TESTING from plone.app.testing import setRoles, TEST_USER_ID from Products.CMFCore.utils import getToolByName from Products.MyProduct.browser.promoboardhome import PromoBoardHome class TestPromoBoardHome(unittest.TestCase): layer = PROD_INTEGRATION_TESTING def setUp(self): self.portal = self.layer['portal'] def test_call(self): pbh = self.portal.restrictedTraverse('@@promoboardhome') try: pbh() except KeyError: print "that didn't work!" import pdb; pdb.set_trace() ``` Am I doing something wrong here?