Import all methods to a unittest file - python

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.

Related

Python unittest a search function

I am trying to write unit tests for my search function which searches through a directory and returns a list of matching files which matches the query. While writing unit tests I realized that if I give it test data, the test data might just take up too much space. How can i get over this problem ? I thought of mocking test data but I am not familiar on how to do this. This is currently how one of my unit tests looks like
import search_function
import unittest
class searchDirTest(unittest.TestCase):
def setUp(self):
pass
def test_file_name_case_sensitive(self):
res = search_function.search_function('./testData', 'allsmall')
self.assertEquals(res, ['./testData/allsmall.txt', './testData/testData_subdir/allsmall.txt'])
self.assertNotEquals(res, ['./testData/ALLSMALL.txt'])
if __name__ == "__main__":
unittest.main()
Also the search_function takes 2 arguments. The Path and the search query. Any pointers on how to achieve this ?
I would suggest refactoring your search_function so that it accepts a list of file names and returns all file names that match, something like case_insensitive_file_match(filenames). This is easily testable and the test data is simple to produce
Testing things external to your program should preferably be kept out of unit tests. This includes reading files/calling APIs etc

Is it possible to make pytest report if a function is never called directly in a test?

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

Can I force `import mymodule` to only import definitions and classes, and not modules (dependencies) imported in the first few lines?

I'm a beginner to python, and have written a module that looks something like this:
# filename: mymodule.py
import numpy as np
from datetime import datetime
def a():
...<stuff>...
def b():
...<stuff>...
The consensus in this thread generally (and in agreement with PEP8) seems to be that import statements should be at the file header. However, now when I import mymodule, running dir(mymodule) shows that objects np and datetime are part of mymodule -- which offhand, seems inefficient and "sloppy". It seems one way to preserve only classes and defs would be some kind of conditional deletion via dynamic iteration over globals() (which after trying and failing for a bit, seems really elusive), or just use the del keyword on everything.
The main question: can I do this, and can I do this dynamically instead of explicitly? Don't the defs work independently, regardless of whether the header modules are part of the import? Otherwise from <x> import <y> would break every time, I would think.

unit testing protected class methods in python?

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()

pytest fixture of fixtures

I am currently writing tests for a medium sized library (~300 files).
Many classes in this library share the same testing scheme which were coded using pytest:
File test_for_class_a.py:
import pytest
#pytest.fixture()
def setup_resource_1():
...
#pytest.fixture()
def setup_resource_2():
...
#pytest.fixture()
def setup_class_a(setup_resource_1, setup_resource_2):
...
def test_1_for_class_a(setup_class_a):
...
def test_2_for_class_a(setup_class_a):
...
similar files exist for class_b, class_c etc ... The only difference being the content of setup_resource_1 & setup_resource_2.
Now I would like to re-use the fixtures setup_class_a, setup_class_b, setup_class_c defined in test_for_class_a.py, test_for_class_b.py and test_for_class_c.py to run tests on them.
In a file test_all_class.py, this works but it is limited to one fixture per test:
from test_for_class_a import *
#pytest.mark.usefixtures('setup_class_a') # Fixture was defined in test_for_class_a.py
def test_some_things_on_class_a(request)
...
But I am looking for a way to perform something more general:
from test_for_class_a import *
from test_for_class_b import * # I can make sure I have no collision here
from test_for_class_c import * # I can make sure I have no collision here
==> #generate_test_for_fixture('setup_class_a', 'setup_class_b', 'setup_class_c')
def test_some_things_on_all_classes(request)
...
Is there any way to do something close to that?
I have been looking at factories of factories and abstract pytest factories but I am struggling with the way pytest defines fixture.
Is there any way to solve this problems?
We had same problem at work and I was hoping to write fixture just once for every case. So I wrote plugin pytest-data which does that. Example:
#pytest.fixture
def resource(request):
resource_data = get_data(reqeust, 'resource_data', {'some': 'data', 'foo': 'foo'})
return Resource(resource_data)
#use_data(resource_data={'foo': 'bar'})
def test_1_for_class_a(resource):
...
#use_data(resource_data={'foo': 'baz'})
def test_2_for_class_a(resource):
...
What's great about it is that you write fixture just once with some defaults. When you just need that fixture/resource and you don't care about specific setup, you just use it. When you need in test some specific attribute, let's say to check out if that resource can handle also 100 character long value, you can pass it by use_data decorator instead of writing another fixture.
With that you don't have to care about conflicts, because everything will be there just once. And then you can use conftest.py for all of your fixtures without importing in test modules. For example we did separate deep module of all fixtures and all included in top conftest.py.
Documentation of plugin pytest-data: http://horejsek.github.io/python-pytest-data/
One solution I found is to abuse the test cases as following:
from test_for_class_a import *
from test_for_class_b import *
from test_for_class_c import *
list_of_all_fixtures = []
# This will force pytest to generate all sub-fixture for class a
#pytest.mark.usefixtures(setup_class_a)
def test_register_class_a_fixtures(setup_class_a):
list_of_fixtures.append(setup_class_a)
# This will force pytest to generate all sub-fixture for class b
#pytest.mark.usefixtures(setup_class_b)
def test_register_class_b_fixtures(setup_class_b):
list_of_fixtures.append(setup_class_b)
# This will force pytest to generate all sub-fixture for class c
#pytest.mark.usefixtures(setup_class_c)
def test_register_class_b_fixtures(setup_class_c):
list_of_fixtures.append(setup_class_c)
# This is the real test to apply on all fixtures
def test_all_fixtures():
for my_fixture in list_of_all_fixtures:
# do something with my_fixture
This implicitly rely on the fact that all test_all_fixture is executed after all the test_register_class*. It is obviously quite dirty but it works...
I think, only pytest_generate_test() (example) could give you such power of customization:
def pytest_generate_tests(metafunc):
if 'db' in metafunc.funcargnames:
metafunc.addcall(param="d1")
metafunc.addcall(param="d2")
EDIT: Ooops, answered the question that older than python experience I have o.O

Categories