I am trying to import a class, than test a method (production_warning) from that class by passing in values 'stage', 'prod' to see if it returns the expected results.
import runner
test=runnerData(force_redeploy=False, pfactor=None, preview=True)
def production_warning_test():
assert.test.production_warning('stage') not errors
assert.test.production_warning('prod') contains "warning"
#run unit test
productionwarningtest()
I am clearly using assert completely wrong here, how do I properly accomplish what I'm trying to do with assert.
To do this with asserts, you'd want to change your assert statements to something like:
assert test.production_warning('stage') is not errors
assert test.production_warning('prod') contains "warning"
I'd highly recommend looking into the python unit test module instead though.
In which case you'd want something like this (note runnerData will need to be in scope, I'm just copying from your question above):
import runner
import unittest
class TestRunner(unittest.TestCase):
def setUp(self):
self.test = runnerData(force_redeploy=False, pfactor=None, preview=True)
def test_production_warning(self):
self.assertTrue(self.test.production_warning('stage') is not errors)
self.assertTrue(self.test.production_warning('prod') contains "warning")
if __name__ == '__main__':
unittest.main()
Related
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.
Example
def main(p):
if foo_a(p):
return False
return p**2
def foo_a(p):
return p % 11 == 0
Now you can get 100% test coverage by
import unittest
from script import main
class Foobar(unittest.TestCase):
def test_main(self):
self.assertEquals(main(3), 9)
But maybe one wanted foo_a to be p % 2 == 0 instead.
The question
Branch coverage would shed a light on it, but I would also like to know if a function was never called "directly" by a test (such as main is in the example), but only indirectly (such as foo_a in the example).
Is this possible with pytest?
First of all just general line of thought is to unittest foo_a as well
import unittest
from script import main, foo_a
class Foobar(unittest.TestCase):
def test_main(self):
self.assertEquals(main(3), 9)
def test_foo_a(self):
self.assertEquals(foo_a(11), True)
You are probably looking for https://coverage.readthedocs.io/en/coverage-4.5.1/ which can be used with pytest https://pypi.org/project/pytest-cov/, this tool can show you exactly which lines of code had been called during testing
But I think there is another way to check your problem it is called mutation testing, here are some libraries that could help you with it
https://github.com/sixty-north/cosmic-ray
https://github.com/mutpy/mutpy
And also look into property based testing libraries like https://github.com/HypothesisWorks/hypothesis/tree/master/hypothesis-python
I have a class with some #staticmethod's that are procedures, thus they do not return anything / their return type is None.
If they fail during their execution, they throw an Exception.
I want to unittest this class, but I am struggling with designing positive tests.
For negative tests this task is easy:
assertRaises(ValueError, my_static_method(*args))
assertRaises(MyCustomException, my_static_method(*args))
...but how do I create positive tests? Should I redesign my procedures to always return True after execution, so that I can use assertTrue on them?
Without seeing the actual code it is hard to guess, however I will make some assumptions:
The logic in the static methods is deterministic.
After doing some calculation on the input value there is a result
and some operation is done with this result.
python3.4 (mock has evolved and moved over the last few versions)
In order to test code one has to check that at least in the end it produces the expected results. If there is no return value then the result is usually stored or send somewhere. In this case we can check that the method that stores or sends the result is called with the expected arguments.
This can be done with the tools available in the mock package that has become part of the unittest package.
e.g. the following static method in my_package/my_module.py:
import uuid
class MyClass:
#staticmethod
def my_procedure(value):
if isinstance(value, str):
prefix = 'string'
else:
prefix = 'other'
with open('/tmp/%s_%s' % (prefix, uuid.uuid4()), 'w') as f:
f.write(value)
In the unit test I will check the following:
open has been called.
The expected file name has been calculated.
openhas been called in write mode.
The write() method of the file handle has been called with the expected argument.
Unittest:
import unittest
from unittest.mock import patch
from my_package.my_module import MyClass
class MyClassTest(unittest.TestCase):
#patch('my_package.my_module.open', create=True)
def test_my_procedure(self, open_mock):
write_mock = open_mock.return_value.write
MyClass.my_procedure('test')
self.assertTrue(open_mock.call_count, 1)
file_name, mode = open_mock.call_args[0]
self.assertTrue(file_name.startswith('/tmp/string_'))
self.assertEqual(mode, 'w')
self.assertTrue(write_mock.called_once_with('test'))
If your methods do something, then I'm sure there should be a logic there. Let's consider this dummy example:
cool = None
def my_static_method(something):
try:
cool = int(something)
except ValueError:
# logs here
for negative test we have:
assertRaises(ValueError, my_static_method(*args))
and for possitive test we can check cool:
assertIsNotNone(cool)
So you're checking if invoking my_static_method affects on cool.
I am not if this is right to but, I have this so far and I am trying to write unittest for this.
def ValidateInputs(self, class_column_name,):
class_column_name_ok = type(class_column_name) is str
if not class_column_name_ok:
raise(TypeError("Argument class_column_name must be a string type"))
I did this for this unittest but again with not having enough knowledge I am not sure. Any help will be much appreciated
def testClassColumnName(self):
self.assertTrue(type(class_column_name), "str")
Without knowing what you do with these values, I can't say 100%. I'll assume you bind them to the class, then provide the unittests I'd write.
Application code:
class MyClass(object):
"""This is my object, this is what it does"""
def validate_inputs(self, merge_columns, class_column_name):
"""some handy docstring"""
if not isinstance(class_column_name, str):
raise TypeError('Argument class_column_name must be a string, supplied {0}'.format(type(class_column_name))
self.class_column_name = class_column_name
unittests (using unittest form the stdlib):
import unittest
class TestMyClass(unittest.TestCase):
def setUp(self):
self.myclass = MyClass() # cheap way to always have a 'clean class' for testing
def test_validate_input_type_string(self):
"""Happy path test when input is correct, and everything works"""
self.myclass.validate_input(merge_columns='some-columns', class_column_name='some_column_name')
self.assertEqual(True, isinstance(self.myclass.class_column_name, str))
def test_validate_input_raises_typerror(self):
"""We raise TypeError if input != string"""
self.assertRaises(TypeError,
self.myclass.validate_input,
merge_columns=1234,
class_column_name=4321)
if __name__ == '__main__':
unittest.main()
General tips for unittesting:
A) Use self.assertEqual(A, B) -> the output on failure will give you some clue on why it failed. Using something like self.assertTrue normaly just outputs an error message like "False is not True"; which is, while 100% accurate, not very useful.
B) Supplying all positional args as key-word args -> makes reading the test later easier.
C) One assert per test case (two at the very most) -> more than this tends to get your test code too complex. Test should be so simple that anyone (even that intern that was just hired from a 3 month coding bootcamp) can figure them out. It's really painful to rewrite a hole test suite (or spend hours updating test code) b/c of a 10 minute update to application code.
Hope this is helpful.
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)