Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter tests after discover

I'm currently running my tests like this:

tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner().run(tests)

Now I want to run a specific test knowing his name (like test_valid_user) but not knowing his class. If there is more than one test with such name than I would like to run all such tests. Is there any way to filter tests after discover?

Or maybe there are other solutions to this problem (please note that it shouldn't be done from command line)?

like image 793
Qumeric Avatar asked Jul 04 '16 11:07

Qumeric


People also ask

How do I ignore tests in xUnit?

xUnit.net does not require an attribute for a test class; it looks for all test methods in all public (exported) classes in the assembly. Set the Skip parameter on the [Fact] attribute to temporarily skip a test.

What is TestCategory C#?

Effectively, using TestCategory lets you create a group of tests using any arbitrary system you want. This allows you to create (and run!) groups of tests that you feel are related without having to run every test in a class, a project or a solution.


2 Answers

You can use the unittest.loader.TestLoader.testMethodPrefix instance variable to change the test methods filter according to a different prefix than "test".

Say you have a tests directory with this king of unit tests:

import unittest


class MyTest(unittest.TestCase):
    def test_suite_1(self):
        self.assertFalse("test_suite_1")

    def test_suite_2(self):
        self.assertFalse("test_suite_2")

    def test_other(self):
        self.assertFalse("test_other")

You can write your own discover function to discover only test functions starting with "test_suite_", for instance:

import unittest


def run_suite():
    loader = unittest.TestLoader()
    loader.testMethodPrefix = "test_suite_"
    suite = loader.discover("tests")
    result = unittest.TestResult()
    suite.run(result)
    for test, info in result.failures:
        print(info)


if __name__ == '__main__':
    run_suite()

remark: the argument "tests" in the discover method is a directory path, so you may need to write a fullpath.

As a result, you'll get:

Traceback (most recent call last):
  File "/path/to/tests/test_my_module.py", line 8, in test_suite_1
    self.assertFalse("test_suite_1")
AssertionError: 'test_suite_1' is not false

Traceback (most recent call last):
  File "/path/to/tests/test_my_module.py", line 11, in test_suite_2
    self.assertFalse("test_suite_2")
AssertionError: 'test_suite_2' is not false
like image 83
Laurent LAPORTE Avatar answered Oct 11 '22 13:10

Laurent LAPORTE


Another simpler way, would be to use py.test with the -k option which does a test name keyword scan. It will run any tests whose name matches the keyword expression.

Although that is using the command-line which you didn't want, please not that you can call the command-line from your code using subprocess.call to pass any arguments you want dynamically.

E.g.: Assuming you have the following tests:

def test_user_gets_saved(self): pass
def test_user_gets_deleted(self): pass
def test_user_can_cancel(self): pass

You can call py.test from cli:

$ py.test -k "test_user"

Or from code:

return_code = subprocess.call('py.test -k "test_user"', shell=True)
like image 34
fips Avatar answered Oct 11 '22 12:10

fips