问题
I have a Pyramid app that I'm still trying to learn. I'm supposed to write unit tests for it but I don't know how to build a request.
I see that Pyramid has a test module with a DummyRequest
but this is blank and obviously if I pass that into the views it will fail because it's not populated with the attributes that the request would have while running.
So the question is, how to I pass a request that looks like a run-time request while testing?
回答1:
The thing to realize whenever you are unit testing (which is different from functional tests) is that you are testing a small "unit". This unit (your view in this case) does not require a "real" request, nor does it require a fully working system. That view has certain expectations of what an object calling itself a "request" may have, but that's about it, and it certainly doesn't require everything available in a real request. This is where mocking, or dummy objects come into play. You want to test your view, so you can pass something into your view with the properties it needs to check if it's doing the job. Let's say you have the following configuration:
def main():
config = Configurator()
config.add_route('user', '/users/{uid}')
return config.make_wsgi_app()
@view_config(route_name='user', renderer='user_template.mako')
def user_view(request):
uid = request.matchdict['uid']
user = find_user(request, uid)
if user is None:
raise HTTPNotFound
return {'user': user}
def find_user(request, uid):
return request.db.query(User).filter_by(id=uid).first()
Great, so this is a real view and you'll notice that it only requires the request to have 2 attributes, matchdict
and db
. Well we can do that:
class Test_user_view(unittest.TestCase):
def test_it(self):
req = DummyRequest()
req.db = DummyDB()
req.matchdict = {'uid': '3'}
result = user_view(req)
self.assertEqual(result['user'].id, 3)
Now the one thing we don't address here is the implementation of DummyDB
but a better approach might be to mock out find_user
to return a dummy value. This keeps the test simple and focused on the view itself without getting bogged down in talking to the database. That's a separate test.
Other answers here cover functional testing more thoroughly and you should certain look at using WebTest to help with ensuring that your entire application is working as you expect it to, but this is not the realm of a unit test.
回答2:
Check out the Pyramid unit vs integration vs functional testing and Pyramid testing guidelines, if you haven't done so already. IMHO, starting with functional tests, as opposed to unit tests with DummyRequest, tends to give better results in many cases (ie. easier to implement and maintain). I'd recommend using either the Webtest (examples in pyramid docs) or Selenium libraries (or a combination of both). Using webtest will allow you to test basic functionality and tests will generally run faster than Selenium. Selenium can actually launch browsers and allows for more granular controls. Because it launches a browser, selenium tests tend to take longer to run. I think a good rule of thumb is that if you just need basic testing (eg. seeing if a particular page loads) then stick with Webtest. If your test requires more control over the browser (eg. debugging javascript), try Selenium. Check out the documents linked above, for examples on how to test with these libraries.
回答3:
You can build up a 'fake' request like this in the setUp function:
request = testing.DummyRequest()
request.errors = errors.Errors([])
request.validated = {}
Then in one of your tests set parameters you want to test against. Like this:
request.GET['app_id'] = 'xxxxxxxxx'
valid_register(request)
self.assertTrue('app_id' in request.validated)
Hope this helps
回答4:
I think Brian's answer is good, but would add that "Write As Much Easily Testable Code As Possible" is a useful mantra. To the extent that you can make functionality modular and write portable libraries that are easily unit-testable with the non-request-dependent means you are familiar with, you will be happy.
Functional tests are an order of magnitude harder and messier slower and less nice than unit tests; Webtest, as Brian mentioned, is where it's at for Pyramid. Selenium is yet another order of magnitude harder and messier and slower. Be careful; if your tests rely on actual data, they will break over time as data changes. Mocking and good dummy data can help with that. Use the higher-level, more difficult forms of testing where necessary, but not just for fun -- you can to some degree use your architecture to reduce the need for it.
To answer the actual 'how do you' question: if you've got something like Webtest, you just do some setup and then do something like
response = app.get('/form.html')
then you have a handy response object with all the info you could wish for on it, and then you write your assertions. the tutorial in the docs is going to explain better than I.
来源:https://stackoverflow.com/questions/13484061/how-to-get-an-actual-pyramid-request-when-unit-testing