Run pytest test in main while using fixture - python

I am currently using pytest to implement tests for hardware which will perform communication among other things. I am also using the record_property fixture to record some values. The test is defined like this:
def test_comm_ytcb_to_ytpb(record_property):
To debug this test I would like to run it like follows from within PyCharm:
if __name__ == '__main__':
test_comm_ytcb_to_ytpb()
Yet, Python will yield the following exception in the console:
TypeError: test_comm_ytcb_to_ytpb() missing 1 required positional argument: 'record_property'
Of course, the error is justified but what do I need so I can continue debugging just like I did without the record_property fixture. I don't mind if nothing is logged or written but I would like to continue debugging the way I did
EDIT:
I just found out that this seems to work:
if __name__ == '__main__':
def record_property(a, b):
return
test_comm_ytcb_to_ytpb(record_property)
Is that ... acceptable?

Related

#unittest.skip(reason) can't work on main function

I'd like to prevent/skip some tests cases during runinng others in python. I couldn't achive to use #unittest.skip(reason) on my case. It always generates a Script Error in python unittest.
My code;
import unittest
#unittest.skip("something")
def main():
try:
something = []
for _ in range(4):
test.log("something happened")
The result is;
Error Script Error
Detail: SkipTest: something
Do you have any idea about the issue?
Unittest is a module that act as testing framework. You should use it according to the framework practices (taken from tutorialspoint.com):
import unittest
def add(x,y):
return x+y
class SimpleTest(unittest.TestCase):
#unittest.skip("demonstrating skipping")
def testadd1(self):
self.assertEquals(add(4,5),9)
if __name__ == '__main__':
unittest.main()
Squish test scripts written in Python are unrelated to the unittest module. I cannot tell how the two could be used together.
Squish offers the test.skip() function for skipping test cases:
test.skip(message);
test.skip(message, detail);
This function skips further execution of the current script test case, or the current BDD scenario (or BDD scenario outline iteration), by throwing an exception and adding a SKIPPED entry to Squish's test log with the given message string, and with the given detail, if provided. If the test case logged verification failures before the skip, it is still considered failed.

Why doesn't the test work without if __name__ == '__main__'?

I can't figure out why without the line if __name__ == '__main__': before unittest.main() the test does not find?
I am using the latest version of PyCharm. I know that in order for the test to work in PyCharm, you can not add these lines at all, but I want to deal with the logic itself: why without the line if __name__ == '__main__': the result is as in the screenshot, but if you add it, then everything works?
Code:
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""Tests for 'name_function.py'."""
def test_first_last_name(self):
"""Are names like 'Janis Joplin' working correctly?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
unittest.main()
There is only one function in the name_function module:
def get_formatted_name(first, last):
"""Builds a formatted full name."""
full_name = f"{first} {last}"
return full_name.title()
Result:
No tests were found
/Users/xxx/Documents/PycharmProjects/Book/venv/bin/python
"/Applications/PyCharm
CE.app/Contents/plugins/python-ce/helpers/pycharm/_jb_unittest_runner.py"
--path /Users/xxx/Documents/PycharmProjects/Book/testing.py
Testing started at 00:22 ...
-------------------------------------------------------------------> Ran 0 tests in 0.000s
OK
Launching unittests with arguments python -m unittest
/Users/xxx/Documents/PycharmProjects/Book/testing.py in
/Users/xxx/Documents/PycharmProjects/Book
Process finished with exit code 0
Empty suite
Empty suite
I am running the testing.py module as the main program, but judging by the answer line PyCharm is running the test via python -m unittest testing.NamesTestCase
I additionally checked the value of the global variable __name__ and indeed it has the value testing, as if testing was imported. Although I launch it initially.
Please explain why in this case the startup script differs from the standard one and when testing.py starts it runs it through unittest? I really want to finally understand this issue. Also don't understand why, in this case, if it initially runs through unittest, unittest.main() doesn't run normally without additional checking if __name__ == '__main__':?

Count subtests in Python unittests separately

Since version 3.4, Python supports a simple subtest syntax when writing unittests. A simple example could look like this:
import unittest
class NumbersTest(unittest.TestCase):
def test_successful(self):
"""A test with subtests that will all succeed."""
for i in range(0, 6):
with self.subTest(i=i):
self.assertEqual(i, i)
if __name__ == '__main__':
unittest.main()
When running the tests, the output will be
python3 test_foo.py --verbose
test_successful (__main__.NumbersTest)
A test with subtests that will all succeed. ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
However, in my real world use cases, the subtests will depend on a more complex iterable and check something which is very different for each subtest. Consequently, I would rather have each subtest counted and listed as a separated test case in the output (Ran 6 tests in ... in this example) to get the full picture.
Is this somehow possible with the plain unittest module in Python? The nose test generator feature would output each test separately but I would like to stay compatible with the standard library if possible.
You could subclass unittest.TestResult:
class NumbersTestResult(unittest.TestResult):
def addSubTest(self, test, subtest, outcome):
# handle failures calling base class
super(NumbersTestResult, self).addSubTest(test, subtest, outcome)
# add to total number of tests run
self.testsRun += 1
Then in NumbersTest override the run function:
def run(self, test_result=None):
return super(NumbersTest, self).run(NumbersTestResult())
Sorry I cannot test this in a fully working environment right now, but this should do the trick.
Using python 3.5.2, themiurge's answer didn't work out-of-the-box for me but a little tweaking got it to do what I wanted.
I had to specifically get the test runner to use this new class as follows:
if __name__ == '__main__':
unittest.main(testRunner=unittest.TextTestRunner(resultclass=NumbersTestResult))
However this didn't print the details of the test failures to the console as in the default case. To restore this behaviour I had to change the class NumbersTestResult inherited from to unittest.TextTestResult.
class NumbersTestResult(unittest.TextTestResult):
def addSubTest(self, test, subtest, outcome):
# handle failures calling base class
super(NumbersTestResult, self).addSubTest(test, subtest, outcome)
# add to total number of tests run
self.testsRun += 1

Python unittest report passed test

Hello I have a test module like the following under "test.py":
class TestBasic(unittest.TestCase):
def setUp(self):
# set up in here
class TestA(TestBasic):
def test_one(self):
self.assertEqual(1,1)
def test_two(self):
self.assertEqual(2,1)
if __name__ == "__main__":
unittest.main()
And this works pretty good, but I need a way to print which test passed, for example I could print the output to the console:
test_one: PASSED
test_two: FAILED
Now the twist, I could add a print statement right after the self.assertEqual() and that would be a passed test and I could just print it, but I need to run the test from a different module, let's say "test_reporter.py" where I have something like this:
import test
suite = unittest.TestLoader().loadTestsFromModule(test)
results = unittest.TextTestRunner(verbosity=0).run(suite)
at this point with results is when I build a report.
So please any suggestion is welcome
Thanks !!
Like Corey's comment mentioned, if you set verbosity=2 unittest will print the result of each test run.
results = unittest.TextTestRunner(verbosity=2).run(suite)
If you want a little more flexibility - and you might since you are creating suites and using test runners - I recommend that you take a look at Twisted Trial. It extends Python's unittest module and provides a few more assertions and reporting features.
Writing your tests will be exactly the same (besides subclassing twisted.trial.unittest.TestCase vs python's unittest) so your workflow won't change. You can still use your TestLoader but you'll have the options of many more TestReporters http://twistedmatrix.com/documents/11.1.0/api/twisted.trial.reporter.html.
For example, the default TestReporter is TreeReporter which returns the following output:

Run python unit tests as an option of the program

I'm a noob in python.
I'm kind of confused about how the python unit test are supposed to be built and run for the actual applications, i.e. if I have a program that starts from a main method I should be able to start unit tests for this program via the same entry point?
So I'm trying to create a program one of the parameters for which should tell the program to run unit tests instead of normal execution (see below) but also being able to accept all parameters that unittest.main() can accept. I would appreciate any advice about better approach of separating the actual program execution and unit tests in pythonic way or any help with the example below if the approach I'm taking is correct:
class MyClass
def write_to_file(self, file):
open(file, 'w').write("Hello world!")
class MyClassTest (unittest.TestCase)
self.mc = MyClass()
self.test_file = os.path.join(os.path.curdir, "a_file.txt")
def setUp(self):
pass
def test_write_to_file(self):
try:
write_to_file(self.test_file)
except IOError:
self.fail("Error!")
if __name__== "__main__":
parser = argparse.ArgumentParser(description="Some desc")
group = parser.add_mutually_exclusive_group()
group.add_argument("-w", "--write", help=': write hello world to given file')
group.add-argument("-t", "--test", help=': run unit tests, use "all" to run all tests')
args = parser.parse_args(sys.argv[1:])
mcl = MyClass()
if args.write:
mcl.write_to_file(args.write)
# below is the questionnable part
if args.test:
#removing -t or --test argument because otherwise unittest.main() will complain
del sys.argv[1:]
if args.test == "all":
unittest.main()
else:
# Adding the argument that was specified after the -t into the sys.argv to be picked up by the unittest.main() - doesn't work correctly (1)
sys.argv.append(args.test)
unittest.main()
(1) If I'm specifying executing MyClass with -t MyTestCase option i expect it to be able to run in accordance with the help message unittest.main() but it says there is an AttributeError: 'module' object has no attribute MyTestCase
Thanks!
I would put the class (the "unit" under test) in a file by itself, and the "main" program and unit tests in two more files. The latter would be executable scripts; the first would simply be imported by them.

Categories