dnraikes
dnraikes

Reputation: 335

how to parameterize unittest test methods

I have a set of python/selenium/unittest tests contained in a single class:

class TestProject(unittest.TestClass):
    def test001_create_project(self):
        ...
    def test002_project_wizard_page1(self, projectName, projectDescription):
        ....
    def test003_project_wizard_page2(self):
        ....
    def test004_project_wizard_finish(self):
        ....

I need to run the test methods in a block in the above order because they walk through a wizard on my web application. However, I want to be able to pass a variety of parameters to the test methods like projectName, projectDescription, etc. Using unittest, how can I run a set of maybe 10 iterations of the tests passing in different parameters to test002_project_wizard_page1?

Upvotes: 3

Views: 13017

Answers (4)

MrName
MrName

Reputation: 2529

Any reason that you cannot use pytest? It provides this functionality out of the box.

Upvotes: 2

Faboor
Faboor

Reputation: 1383

Take a look at Python unit testing: parametrized test cases post on Eli Bendersky's blog. It states that

You can't easily pass arguments into a unittest.TestCase from outside.

However, it provides an implementation for class ParametrizedTestCase(unittest.TestCase) which can be used to add parameters to the unittest.TestCase class. That will solve your parameters problem and I believe, each individual test methods are already being run in order.

Upvotes: 1

chepner
chepner

Reputation: 530823

Your numbered tests are really just parts of a single test. What you should define as separate tests are functions that use your parameter sets.

class TestProject(unittest.TestCase):
    def _create_project(self):
        ...
    def _page1(self, projectName, projectDescription):
       ...
    def _page2(self):
       ...
    def _finish(self):
       ...

    def _run(self, name, descr):
        self._create_project()
        self._page1(name, descr)
        self._page2()
        self._finish()

    def test001(self):
        self._run("foo", "do foo")

    def test002(self):
        self._run("bar", "do bar")

    # etc

An interesting module that can reduce some of the boilerplate is the ddt project.

import ddt

@ddt.ddt
class TestProject(unittest.TestCase):
    def _create_project(self):
        ...
    def _page1(self, projectName, projectDescription):
       ...
    def _page2(self):
       ...
    def _finish(self):
       ...

    @ddt.data(
      ("foo", "do foo"),
      ("bar", "do bar"),
      # etc
    )
    @ddt.unpack
    def test_run(self, name, descr):
        self._create_project()
        self._page1(name, descr)
        self._page2()
        self._finish()

Upvotes: 7

Menglong Li
Menglong Li

Reputation: 2255

For me, it looks like you wanna test under a template, with different parameters. How about codes like the following:

import unittest


class TestProject(unittest.TestClass):
    def mytest001_create_project(self):
        ...

    def mytest002_project_wizard_page1(self, projectName, projectDescription):
        ....

    def mytest003_project_wizard_page2(self):
        ....

    def mytest004_project_wizard_finish(self):
        ....

    def mytest_in_order(self, project_name, project_description):
        self.mytest001_create_project()
        self.mytest002_project_wizard_page1(project_name, project_description)
        self.mytest003_project_wizard_page2()
        self.mytest004_project_wizard_finish()

    def test_in_batch(self):
        project_names = ['a', 'b']
        project_descriptions = ['aa', 'bb']

        for project_name, project_description in zip(project_names, project_descriptions):
            self.mytest_in_order(project_name, project_description)

Upvotes: 0

Related Questions