I want to better write this test:
def test_profile_created(self):
self.client.post(reverse('registration_register'), data={
'username':'ygam',
'email':'ygam@example.com',
'password1':'ygam',
'password2':'ygam'
})
"""
Test if a profile is created on save
"""
user = User.objects.get(username='ygam')
self.assertTrue(UserProfile.objects.filter(user=user).exists())
and I just came upon this code on django-registration tests that does not actually “create” the user:
def test_registration_signal(self):
def receiver(sender, **kwargs):
self.failUnless('user' in kwargs)
self.assertEqual(kwargs['user'].username, 'bob')
self.failUnless('request' in kwargs)
self.failUnless(isinstance(kwargs['request'], WSGIRequest))
received_signals.append(kwargs.get('signal'))
received_signals = []
signals.user_registered.connect(receiver, sender=self.backend.__class__)
self.backend.register(_mock_request(),
username='bob',
email='bob@example.com',
password1='secret')
self.assertEqual(len(received_signals), 1)
self.assertEqual(received_signals, [signals.user_registered])
However he used a custom function for this “_mock_request”:
class _MockRequestClient(Client):
def request(self, **request):
environ = {
'HTTP_COOKIE': self.cookies,
'PATH_INFO': '/',
'QUERY_STRING': '',
'REMOTE_ADDR': '127.0.0.1',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': 'testserver',
'SERVER_PORT': '80',
'SERVER_PROTOCOL': 'HTTP/1.1',
'wsgi.version': (1,0),
'wsgi.url_scheme': 'http',
'wsgi.errors': self.errors,
'wsgi.multiprocess':True,
'wsgi.multithread': False,
'wsgi.run_once': False,
'wsgi.input': None,
}
environ.update(self.defaults)
environ.update(request)
request = WSGIRequest(environ)
# We have to manually add a session since we'll be bypassing
# the middleware chain.
session_middleware = SessionMiddleware()
session_middleware.process_request(request)
return request
def _mock_request():
return _MockRequestClient().request()
However, it may be too long of a function for my needs. I want to be able to somehow “fake” the account creation. I have not much experience on mocks and stubs so any help would do. Thanks!
These two approaches are testing different things:
Your test case tests the model layer — it asks the question “if I create a user and save it, does the profile record get created automatically?”
It doesn’t depend on how the user object was created — Through an admin view, or a user signup view, or a management command — as long as this test passes, you know that any method of creating a user through the ORM will add a profile.
It also doesn’t care how the profile is created. It could be through a pre-save signal, a post-save signal, some code in an overridden save() method, or magic. As long as the record is created, the test will pass.
The code you found in django-registration is testing the view layer. It is calling a specific view function,
register, passing it three URL parameters, and asking the question “did theuser_registeredsignal get fired as a result of this view?”This test case doesn’t look at other methods of creating a user; just the registration view. It’s not concerned with any other methods of creating a user.
It also doesn’t look at whether a profile was created. All it wants to know is that the signal was fired, regardless of what that signal actually does in any particular application.
What’s the difference?
Your code is a great example of an integration test — “Did I put all of these parts (models, signals) together in right order so that profiles get created?” — and of a regression test, to signal you in the future whether you’ve done anything that has broken the user profile creation.
The django-registration code is an actual unit test. It very carefully isolates just the view code, to call it in a controlled environment and ask one simple question of it.
Which is better?
In your case, you probably don’t need to write the unit test. (Though there could be a lot of debate about that; it’s practically a matter of religion in some parts) You want a way to verify that the code that pieces that you’ve put together are working as you expect them to, and your test is the best way to do that.
Don’t worry about actually creating a user — during the test run, you’re doing everything in a transaction, and that transaction is rolled back immediately after the test method completes. It may not even hit the disk. And, as @Platinum Azure mentioned, it’s all on a test database anyway.