How to write test that have same code in the beginning?
I am writing test automation for the application that have following features
- Create News
- Create Event
In Create News and Create Event I have to repeat login code. Is there a way to use login code that I have already written.
class LoginTest(unittest.TestCase): @classmethod def setUp(cls): cls.browser = webdriver.Chrome() cls.browser.get(vars_login_test.base_url) print 'login Page loaded' def test_login_pass(self): ''' login code goes here ''' @classmethod def tearDown(cls): # close the browser window cls.browser.quit() if __name__ == '__main__': unittest.main(verbosity=2) # run all tests as main
Create News code
class CreateNews(unittest.TestCase): @classmethod def setUp(cls): cls.browser = webdriver.Chrome() cls.browser.get(vars_login_test.base_url) print("login Page loaded") def test_login_pass(self): ''' login code goes here ''' ''' rest of the code (code to create news) ''' @classmethod def tearDown(cls): # close the browser window cls.browser.quit() if __name__ == '__main__': unittest.main(verbosity=2) # run all tests as main
Code for Create Event is similar to Create News
Yes, there are a host of techniques to deal with code duplication in tests, especially in setup. Which one(s) you use, especially if you're new to testing, depends on things like how familiar you are with the techniques and how much complexity they end up saving you in your particular application.
Probably the simplest method is to just pull out methods to do common setup. You might start with a method to create a user in order to test logging in with a correct and an incorrect password. Once you have that covered you might want to just abstract away both of those with a method to create a user and log in with the correct question, to use as setup for any tests which require you to be logged in. You may end up with something looking like this:
def login(user: User, password: str): … def create_user(username: str, password: str) -> User: … def ensure_logged_in() -> User: user = create_user(…) login(…)
Another way is to "package" related setup and teardown in a
TestCasehierarchy, where none of the
*TestCaseclasses have tests of their own (otherwise those tests would be repeated for each subclass). These classes usually have just
tearDownClassmethods. This way of packaging functionality is really handy since it combines all the setup and teardown in easily reusable classes. By the way, your use of
tearDownas class methods is very unorthodox, and I don't think they will work as you expect. You may have classes like
TestCaseclass hierarchy isn't always optimal. One thing you want to avoid is to create the testing "god class" containing all the setup anyone could ever want, and then cherry-picking parts of that setup during tests. This is a nightmare to maintain for several reasons, the biggest one being the complicated interdependencies between the tests, which make test failures hard to debug and the test code resistant to change. They will also run far slower than they would with minimal setup. One answer to this is to create "mixin" classes containing specific bits of setup and teardown. Your test classes can then inherit from exactly the ones of these they need. For example, a test may inherit from
LoggedInRegularUserMixinto test interactions between these two types of users.
You can also reuse whole tests. To test a bunch of separate API permissions, for example, you can create a class with some tests and then subclass that with just some test setup (a legitimate use for inheriting from a class containing tests, unlike the above). A Stack Overflow answer suggested something close to what I ended up using recently (very simplified, except for the
*Testsclasses themselves, which literally ended up just declaring them as test classes):
class RequestPermissionMixin(TestCase): __test__ = False # Never run this class as a test on its own request_factory = APIRequestFactory() def test_should_allow_user_with_permission(self) -> None: … def test_should_not_allow_user_without_permission(self) -> None: … class CreateMixin(RequestPermissionMixin): request_factory_method = RequestPermissionMixin.request_factory.post class UpdateMixin(RequestPermissionMixin): request_factory_method = RequestPermissionMixin.request_factory.post class CanCreateFooTests(CreateMixin, CanModifyFooMixin): __test__ = True class CanUpdateFooTests(UpdateMixin, CanModifyFooMixin): __test__ = True