Unittest and doctest, how to make my files callable? - python

I have a folder with python scripts that contain doc tests that I want to do unit tests on. When I try to test it with one file like this:
import unittest
suite = unittest.TestSuite()
suite.addTest('/homes/ndeklein/workspace/MS/PyMS/pyMS/baseFunctions.py')
unittest.TextTestRunner().run(suite)
I get this error:
TypeError: the test to add must be callable
However, when I do it from the commandline
python '/homes/ndeklein/workspace/MS/PyMS/pyMS/baseFunctions.py'
it works.
How can I make my file callable?

addTest takes a TestCase or a TestSuite - and you're passing in a string.
Have a look at the docs here:
http://docs.python.org/library/unittest.html
It's not clear exactly what you want to do - but if baseFunctions.py defines a subclass of TestCase, you could try this:
import unittest
from baseFunctions import MyTestCase
suite = unittest.TestSuite()
suite.addTest(MyTestCase)
unittest.TextTestRunner().run(suite)

Related

Python 3 how to write unit tests for try except outside functions in modules

I would like to know how to write Python 3 unittest for try exceptblocks
that are defined outside of function definitions in Python's module.
Imagine that in package/module.py I have a block of code like:
import os
try:
CONSTANT = os.environ['NOT_EXISTING_KEY']
except KeyError:
CONSTANT = False
finally:
del os
(please don't mind the actual code, I know I could have used os.getenv('NOT_EXISTING_KEY', False)in this specific case, what I am interested in is really testing that the try-except block in a module (outside of a function) behaves as expected.
How can I write a unit test that checks that package.module.CONSTANT is set to the expected value?
In the unittest file (I use pytest) I have something like:
from package.module import CONSTANT
def test_constant_true():
assert CONSTANT == 'expected_value'
to test that if the try block executed correctly then CONSTANT is as expected.
I don't know, however, how to mock the import machinery so that the os.environ in the try block raises an exception and I can test that CONSTANT is set to False.
How can I do that?
You can use monkeypatch to set the environment variable, but you have to reload the module for the change to take effect:
from importlib import reload
from package import module
def test_constant_true(monkeypatch):
monkeypatch.setenv('MY_KEY', '42')
reload(module)
assert module.CONSTANT == '42'
def test_constant_false():
reload(module)
assert not module.CONSTANT
Given this content of package/module.py:
import os
try:
CONSTANT = os.environ['MY_KEY']
except KeyError:
CONSTANT = False
You could mock the environment using mock.patch.dict and import the value inside your unit test method. Like so:
from unittest import TestCase, mock
class YourTest(TestCase):
#mock.patch.dict('os.environ', {'NOT_EXISTING_KEY': 'value'})
def test_constant_key_defined(self, mocked):
""" Tests when the key is defined """
from package.module import CONSTANT
self.assertEqual(CONSTANT, 'value')
def test_constant_key_not_defined(self):
""" Tests when the key is not defined """
from package.module import CONSTANT
self.assertEqual(CONSTANT, 'value')
You may use the importlib.reload, like #mrbean-bremen's answer, which I am not familiar with.

Import all methods to a unittest file

I'm trying to figure out the best structure to write unittests for a file parser. My parser.py file looks like this:
import re
import sys
import glob
from datetime import datetime
import csv
def main():
# does something
def normalizeGender(gender):
# does something
def normalizeDate(date):
# does something
def parseLine(record, delimiter):
# does something
def formatRecords(record_list):
# does something
etc...
I have tests dir, and inside a parser_test.py file that looks like this:
import unittest
class ParserTest(unittest.TestCase):
# Returns True or False.
def test(self):
self.assertTrue(True)
if __name__ == '__main__':
unittest.main()
Now, if I want to test all the methods from my parser, should import them all at once? Something tells me they should be wrapped as a module of some sort.
The following answer is based on my tool preferences, and the practices that I usually follow:
I would use pytest to implement the tests
I would implement at least 1 test for every function: test_normalizeGender, test_normalizeDate, test_ normalizeDate, test_parseLine, test_formatRecords. However, in case you have if statement with multiple branching inside your code, make sure you try to cover the possible cases of those branches. In addition, if you have for loops, I will implement a test for no elements, one element, and multiple elements.
I will put all the test in the same file since they are related.
Keep in mind that when it comes to implementing unit tests, you are testing a unit, so you don't need to verify the functionality of all your parser in the same test. In addition, you should mock/patch objects, methods, or functions to facilitate testing.
I hope this helps.

How to stop Python unittest from printing test docstring?

I've noticed that, when my Python unit tests contain documentation at the top of the function, sometimes the framework prints them in the test output. Normally, the test output contains one test per line:
<test name> ... ok
If the test has a docstring of the form
"""
test that so and so happens
"""
than all is well. But if the test has a docstring all on one line:
"""test that so and so happens"""
then the test output takes more than one line and includes the doc like this:
<test name>
test that so and so happens ... ok
I can't find where this is documented behavior. Is there a way to turn this off?
The first line of the docstring is used; the responsible method is TestCase.shortDescription(), which you can override in your testcases:
class MyTests(unittest.TestCase):
# ....
def shortDescription(self):
return None
By always returning None you turn the feature off entirely. If you want to format the docstring differently, it's available as self._testMethodDoc.
This is an improved version of MartijnPieters excellent answer.
Instead of overriding that method for every test, it is more convenient (at least for me) to add the following file to your list of tests. Name the file test_[whatever you want].py.
test_config.py
import unittest
# Hides Docstring from Verbosis mode
unittest.TestCase.shortDescription = lambda x: None
This code snippet could also be placed in the __init__.py files of the test folder.
In my case, I just added to the root folder of my project, scripts, since I use discover as in python -m unittest from scripts to run all the unittests of my project. As this is the only test*.py file on that directory level, it will load before any other test.
(I tried the snippet on the __init__.py of the root folder, it didn't seem to work, so I sticked with the file approach)
BTW: I actually prefer lambda x: "\t" instead of lambda x: None
After reading this I made a plugin for nosetests to avoid the boilerplate.
https://github.com/MarechJ/nosenodocstrings

How do I specify a single test in a file with nosetests?

I have a file called test_web.py containing a class TestWeb and many methods named like test_something().
I can run every test in the class like so:
$ nosetests test_web.py
...
======================================================================
FAIL: checkout test
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/me/path/here/test_web.py", line 187, in test_checkout
...
But I can’t seem to run individual tests. These give me “No such test” errors when run in the same PWD:
$ nosetests test_web.py:test_checkout
$ nosetests TestWeb:test_checkout
What could be wrong here?
You must specify it like so: nosetests <file>:<Test_Case>.<test_method>, or
nosetests test_web.py:TestWeb.test_checkout
See the docs
You can also specify a module:
nosetests tests.test_integration:IntegrationTests.test_user_search_returns_users
Specifying names on the command line like the other answers suggest does work and is useful. However, when I'm in the midst of writing tests, I often find that I want to run just the test I'm working on, and the names that I would have to write on the command line get pretty long and cumbersome to write. In such case, I prefer to use a custom decorator and flag.
I define wipd ("work in progress decorator") like this:
from nose.plugins.attrib import attr
def wipd(f):
return attr('wip')(f)
This defines a decorator #wipd which will set the wip attribute on objects it decorates. For instance:
import unittest
class Test(unittest.TestCase):
#wipd
def test_something(self):
pass
Then -a wip can be used at the command line to narrow the execution of the test to the ones marked with #wipd.
Note on names...
I'm using the name #wipd for the decorator rather than #wip to avoid this kind of problem:
import unittest
class Test(unittest.TestCase):
from mymodule import wip
#wip
def test_something(self):
pass
def test_something_else(self):
pass
The import will make the wip decorator a member of the class, and all tests in the class will be selected. The attrib plugin checks the parent class of a test method to see if the attribute selected exists there too, and the attributes that are created and tested by attrib do not exist in a segregated space. So if you test with -a foo and your class contains foo = "platypus", then all tests in the class will be selected by the plugin.
To run multiple specific tests, you can just add them to the command line, separated by space.
nosetests test_web.py:TestWeb.test_checkout test_web.py:TestWeb.test_another_checkout
In my tests, specifying tests with module names do not work
You must specify the actual path to the .py:
nosetests /path/to/test/file.py:test_function
This with nose==1.3.7
My requirement was to run a single test in a test file that was in another windows directory - this was done from the anaconda command prompt as follows:
ran nosetests from:
(base) C:\Users\ABC\Documents\work\
but test_MyTestFile.py and methodsFile.py were in:
(base) C:\Users\ABC\Documents\work\daily\
run single test by including path with quotes as follows:
(base) C:\Users\ABC\Documents\work>nosetests "daily\\test_MyTestFile.py:MyTestClass.test_add_integers"
test_MyTestFile.py looked like this:
import methodsFile
import unittest
class MyTestClass(unittest.TestCase):
def test_add_integers(self):
assert methodsFile.add(5, 3) == 8
def test_add_integers_zero(self):
assert methodsFile.add(3, 0) == 3
methodsFile.py looked like this:
def add(num1, num2):
return num1 + num2

How to get currently running testcase name from testsuite in unittest

How can I get currently running testcase name, while in the testsuite collection there are 16 testcases. Tests are executed sequentially (in the order of adding test to the testSuite collection). When I add all tests to testSuite collection I can preview this object but how can I get currently executing test while tests are running. Maybe some variable holds this information?
example:
def suite():
testSuite= unittest.TestSuite()
testSuite.addTest(FlightsTestCases('test_sel__reservation_one_way_wizzair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_wizzair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_round_wizzair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_tair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_round_tair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_wizzair_credit_card'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_tair_credit_card'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_round_wizzair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_wizzair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_easyjet_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_ryanair_transfer'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_round_ryanair_credit_card'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_tair_duplicated'))
testSuite.addTest(FlightsTestCases('test_reservation_wrong_card_lowcost'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_tair_credit_card'))
testSuite.addTest(FlightsTestCases('test_sel_reservation_one_way_tair_wrong_credit_card'))
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
Tests are executed using Selenium-RC framework.
unittest.TestCase.shortDescription()
Returns a description of the test, or None if no description has been provided. The default implementation of this method returns the first line of the test method’s docstring, if available, or None.
unittest.TestCase.id()
Return a string identifying the specific test case. This is usually the full name of the test method, including the module and class name.
Hopefully one of those is useful for your needs.
unittest.TestCase._testMethodName
Example code:
import unittest
class BasicTests(unittest.TestCase):
def test_print(self):
print(self._testMethodName)

Categories