Since I have been writing tests, I always stuck to the principle of one assertion per test. Now assume I have a simple application where I want to perform a system test with the following three test cases:
- Test if a user can register a new account
- Test if a user can log in
- Test if a logged in user can add a post
I understand that in a unit test all three tests can be performed independently by mocking the other components. However, in a system test, 2. depends on 1., and 3. depends on 2.
I always pondered how to model such dependencies in tests while still maintaining the one assertion per test principle. Up until recently I simply would write three independent test cases, where each necessary step was repeated within the test code. However, this often led to test code duplication and in consequence to hard to maintain test code. So I began to cascade my tests like in this pseudo code example:
def test_register_user(): new_user = app.register new user() assert(new_user in app.list_of_users()) return new_user def test_login(): user = test_register_user() logged_in_user = app.log_in_user(user) assert(logged_in_user in app.list_of_logged_in_users()) return logged_in_user def test_write_post(): app.write_post(text="text", user=test_login()) assert("text" in app.list_posts())
test_write_post() is executed, it will call
test_register_user(). I like this approach because it does reduce test code duplication. However, I am not sure whether it violates the "one assertion per test" principle. On the one hand there is only one assertion that directly belongs to the tested method. On the other hand if you follow the execution path of the test case, several assertion will be checked.
My question is: Does the presented style of cascading tests violate the "one assertion per test" principle? If so, are there any better practices how one can deal with dependencies in system test while keeping the test code maintainable?