简化注册测试,提高清晰度和灵活性
One of our largest test files is `zerver/tests/test_signup.py`, at 2490 lines. It's appropriate to have lots of tests there -- it's really important that signup works correctly, it has a lot of different cases, and it's an area that few members of the Zulip community regularly encounter (because our daily use of Zulip is on accounts that we've already signed up). But a lot of that line count is basically repetition and boilerplate, which makes it hard to understand what's being tested and makes it likely that there are things we aren't testing which we should be. A typical example: def test_signup_existing_email(self) -> None: """ Check if signing up with an email used in another realm succeeds. """ email = self.example_email('hamlet') password = "newpassword" realm = get_realm('lear') result = self.client_post('/accounts/home/', {'email': email}, subdomain="lear") self.assertEqual(result.status_code, 302) result = self.client_get(result["Location"], subdomain="lear") confirmation_url = self.get_confirmation_url_from_outbox(email) result = self.client_get(confirmation_url, subdomain="lear") self.assertEqual(result.status_code, 200) result = self.submit_reg_form_for_user(email, password, subdomain="lear") self.assertEqual(result.status_code, 302) get_user(email, realm) self.assertEqual(UserProfile.objects.filter(email=email).count(), 2) Ideally this test would look more like: def test_signup_existing_email(self) -> None: self.signup(email=self.example_email('hamlet'), realm=get_realm("lear")) self.assertEqual(UserProfile.objects.filter(email=email).count(), 2) All the steps of going through the signup flow, and checking that things look good at each stage, are common to lots of tests and they should be in a common function like my hypothetical `self.signup`. That would (a) make many tests much shorter, and as a bonus (b) help us do *all* those checks every time, for added assurance that the tests aren't missing something. The key to writing a function like this `self.signup` are a couple of principles: * Lots of optional arguments. E.g.: * `realm` would default to `get_realm("zulip")`. * The next test in the file, `test_signup_invalid_name`, passes a funny `full_name` value to `submit_reg_form_for_user`, which in fact is the point of that test -- so `signup` would have an optional argument `full_name`, which that test might be the only user of. * Optional arguments to expect failure. E.g., `test_signup_invalid_name` expects the flow to stop after `submit_reg_form_for_user`. So `signup` would have an optional argument like `fail_reg_form`. To allow the test to do its own inspection of the details of the failure, maybe `signup` would `return result` at that stage -- so the test would look like
内容来源: zulip/zulip