0

I am writing test automation for the application that have following features

  1. Login
  2. Create News
  3. 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.

Login Code

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

1 Answer 1

0

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 TestCase hierarchy, where none of the *TestCase classes have tests of their own (otherwise those tests would be repeated for each subclass). These classes usually have just setUpClass, setUp, tearDown and tearDownClass methods. 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 setUp and tearDown as class methods is very unorthodox, and I don't think they will work as you expect. You may have classes like

  • UserTestCase
  • LoggedInUserTestCase
  • LoggedInUserWithWritePermissionTestCase

A straightforward TestCase class 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 LoggedInAdministratorMixin and LoggedInRegularUserMixin to 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 *Tests classes 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.