How to resolve "ValueError: Empty module name"? - python

In my UnitTest directory, I have two files, mymath.py and test_mymath.py.
mymath.py file:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(numerator, denominator):
return float(numerator) / denominator
And the test_mymath.py file is:
import mymath
import unittest
class TestAdd(unittest.TestCase):
"""
Test the add function from the mymath library
"""
def test_add_integer(self):
"""
Test that the addition of two integers returns the correct total
"""
result = mymath.add(1, 2)
self.assertEqual(result, 3)
def test_add_floats(self):
"""
Test that the addition of two integers returns the correct total
"""
result = mymath.add(10.5, 2)
self.assertEqual(result, 12.5)
def test_add_strings(self):
"""
Test that the addition of two strings returns the two strings as one
concatenated string
"""
result = mymath.add('abc', 'def')
self.assertEqual(result, 'abcdef')
if __name__ == '__main__':
unittest.main()
When I run the command
python .\test_mymath.py
I got the results
Ran 3 tests in 0.000s
OK
But when I tried to run the test using
python -m unittest .\test_mymath.py
I got the error
ValueError: Empty module name
Traceback:
Folder Structure:
I am following this article
My python version is Python 3.6.6 and I am using windows 10 in the local machine.

Use python -m unittest test_mymath

You almost got it. Instead of:
python -m unittest ./test_mymath.py
don't add the ./ so you now have:
python -m unittest test_mymath.py
Your unit tests should now run.

Related

Dynamically create test file templates for your entire repo

I've been looking around, but I haven't been able to find anything that does exactly what I want.
I was wondering if there's a utility out there that scans the structure and source code of your entire repo and creates a parallel test structure where one isn't there already, in which every single function and method in your code has an equivalent empty unit test.
It's pretty tedious to have to manually write a bunch of unit test boilerplate.
For example, assuming this project structure:
myproject
|--src
|--__init__.py
|--a.py
|--subpackage
|--__init__.py
|--b.py
|--c.py
It should create:
myproject
|--src
| |--__init__.py
| |--a.py
| |--subpackage
| |--__init__.py
| |--b.py
| |--c.py
|
|--tests
|--test_a.py
|--subpackage
|--test_b.py
|--test_c.py
And if the contents of a.py are:
class Printer:
def print_normal(self, text):
print(text)
def print_upper(self, text):
print(str(text).upper())
def print_lower(self, text):
print(str(text).lower())
def greet():
print("Hi!")
It the contents of test_a.py should be something similar to this:
import pytest
from myproject.src import a
def test_Printer_print_normal():
assert True
def test_Printer_print_upper():
assert True
def test_Printer_print_lower():
assert True
def test_greet():
assert True
Is anyone aware of any python project that does something like this? Even if it isn't exactly the same, anything that would save some work when initially setting up the pytest boilerplate for a giant repo with hundreds of classes and thousands of methods would be a massive time-saver.
Thanks in advance.
Searching for the tests generator tools in Python myself, I could find only those that generate unittest-style classes:
pythoscope
Installation of the latest version from Github:
$ pip2 install git+https://github.com/mkwiatkowski/pythoscope
Looks promising in theory: generates classes based on static code analysis in modules, maps the project structure to tests dir (one test module per library module), each function gets its own test class. The problem with this project is that it's pretty much abandoned: no Python 3 support, fails when encounters features backported to Python 2, thus IMO unusable nowadays. There are pull requests out there that claim to add Python 3 support, but they didn't work for me back then.
Nevertheless, here's what it would generate if your module would have Python 2 syntax:
$ pythoscope --init .
$ pythoscope spam.py
$ cat tests/test_spam.py
import unittest
class TestPrinter(unittest.TestCase):
def test_print_lower(self):
# printer = Printer()
# self.assertEqual(expected, printer.print_lower())
assert False # TODO: implement your test here
def test_print_normal(self):
# printer = Printer()
# self.assertEqual(expected, printer.print_normal())
assert False # TODO: implement your test here
def test_print_upper(self):
# printer = Printer()
# self.assertEqual(expected, printer.print_upper())
assert False # TODO: implement your test here
class TestGreet(unittest.TestCase):
def test_greet(self):
# self.assertEqual(expected, greet())
assert False # TODO: implement your test here
if __name__ == '__main__':
unittest.main()
Auger
Installation from PyPI:
$ pip install auger-python
Generates tests from runtime behavior. While it may be an option for tools with a command line interface, it requires writing an entrypoint for libraries. Even with tools, it will only generate tests for stuff that was explicitly requested; if a function is not executed, no test will be generated for it. This makes it only partially useable for tools (worst case is that you have to run the tool multiple times with all options activated to cover the completed code base) and hardly useable with libraries.
Nevertheless, this is what Auger would generate from an example entrypoint for your module:
# runner.py
import auger
import spam
with auger.magic([spam.Printer], verbose=True):
p = spam.Printer()
p.print_upper()
Executing the runner.py yields:
$ python runner.py
Auger: generated test: tests/test_spam.py
$ cat tests/test_spam.py
import spam
from spam import Printer
import unittest
class SpamTest(unittest.TestCase):
def test_print_upper(self):
self.assertEqual(
Printer.print_upper(self=<spam.Printer object at 0x7f0f1b19f208>,text='fizz'),
None
)
if __name__ == "__main__":
unittest.main()
Custom tool
For a one-time job, it shouldn't be hard to write own AST visitor that generates the test stubs from existing modules. The example script testgen.py below generates simple test stubs using the same idea as pythoscope. Usage example:
$ python -m testgen spam.py
class TestPrinter:
def test_print_normal(self):
assert False, "not implemented"
def test_print_upper(self):
assert False, "not implemented"
def test_print_lower(self):
assert False, "not implemented"
def test_greet():
assert False, "not implemented"
Contents of testgen.py:
#!/usr/bin/env python3
import argparse
import ast
import pathlib
class TestModuleGenerator(ast.NodeVisitor):
linesep = '\n'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.imports = set()
self.lines = []
self.indent = 0
self.current_cls = None
#property
def code(self):
lines = list(self.imports) + [self.linesep] + self.lines
return self.linesep.join(lines).strip()
def visit_FunctionDef(self, node: ast.FunctionDef):
arg_self = 'self' if self.current_cls is not None else ''
self.lines.extend([
' ' * self.indent + f'def test_{node.name}({arg_self}):',
' ' * (self.indent + 1) + 'assert False, "not implemented"',
self.linesep,
])
self.generic_visit(node)
def visit_ClassDef(self, node: ast.ClassDef):
clsdef_line = ' ' * self.indent + f'class Test{node.name}:'
self.lines.append(clsdef_line)
self.indent += 1
self.current_cls = node.name
self.generic_visit(node)
self.current_cls = None
if self.lines[-1] == clsdef_line:
self.lines.extend([
' ' * self.indent + 'pass',
self.linesep
])
self.indent -= 1
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef):
self.imports.add('import pytest')
self.lines.extend([
' ' * self.indent + '#pytest.mark.asyncio',
' ' * self.indent + f'async def test_{node.name}():',
' ' * (self.indent + 1) + 'assert False, "not implemented"',
self.linesep,
])
self.generic_visit(node)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'module',
nargs='+',
default=(),
help='python modules to generate tests for',
type=lambda s: pathlib.Path(s).absolute(),
)
modules = parser.parse_args().module
for module in modules:
gen = TestModuleGenerator()
gen.visit(ast.parse(module.read_text()))
print(gen.code)

PyTest-Mock not working due to AttributeError

I am trying to use PyTest_Mock in order to do some testing in my Python project. I created a very simple test to try it out, but I am getting an AttributeError and I don't know why.
model.py
def square(x):
return x * x
if __name__ == '__main__':
res = square(5)
print("result: {}".format(res))
test_model.py
import pytest
from pytest_mock import mocker
import model
def test_model():
mocker.patch(square(5))
assert model.square(5) == 25
After running python -m pytest I get a failure and the following error:
def test_model():
> mocker.patch(square(5))
E AttributeError: 'function' object has no attribute 'patch'
test_model.py:7: AttributeError
You don't need to import mocker, it's available as fixture, so you just pass it as a parameter in the test function:
def test_model(mocker):
mocker.patch(...)
square(5) evaluates to 25, so mocker.patch(square(5)) will effectively try to patch a number 25. Instead, pass the function name as parameter: either
mocker.patch('model.square')
or
mocker.patch.object(model, 'square')
Once patched, square(5) will not return 25 anymore since the original function is replaced with a mock object that can return anything and will return a new mock object by default. assert model.square(5) == 25 will thus fail. Usually, you patch stuff either to avoid complex test setup or simulate behaviour of components that is desired in test scenario (for example, a website being unavailable). In your example, you don't need mocking at all.
Complete working example:
import model
def test_model(mocker):
mocker.patch.object(model, 'square', return_value='foo')
assert model.square(5) == 'foo'

Is Python's code marshalling reversible?

Consider the following script:
from marshal import dumps, loads
def square_fn(x):
return x * x
def test_serialize_marshal():
code_string = dumps(square_fn.__code__)
code_string1 = dumps(loads(code_string))
assert code_string == code_string1
Run in Python 3.6 with pytest.
This test is failing on my computer. Why is this so?
I am trying to serialize a Python function in a way that I can test, from its serialized representation, that the function is the same... This test suggests that this is not the case for marshal dumps/loads.
EDIT:
Interestingly, this test passes:
def test_serialize_marshal2():
import types
code = dumps(square_fn.__code__)
ff = types.FunctionType(loads(code), globals())
assert square_fn.__code__ == ff.__code__
which is what this answer tests. However, I do not want the equality of the Python object, but of the string.

Running a Python unittest test on multiple files

I want to add unit testing to the assessment of my high school programming class.
If I have twenty submissions of files that look like this:
def calculateReturn(principle, rate, freq, time):
final = principle * (1 + (rate/freq)) ** (freq * time)
return final
Can I use a test case like this?
import unittest
class test(unittest.TestCase):
def test1(self):
value = calculateReturn(5000, 0.05, 12, 11)
self.assertAlmostEqual(value, 8235.05, 2)
if __name__ == '__main__':
unittest.main()
How do I run this one simple test on twenty modules?
FURTHER INFORMATION
For testing I have created three "submissions" all of which show different ways of calculating x^y.
submission1.py:
from math import pow
def powerFunction(base, power):
result = pow(base, power)
return result
submission2.py:
def powerFunction(base, power):
result = base ** power
return result
submission3.py:
def powerFunction(base, power):
result = 1
for i in range(power):
result = result * base
return result
The test code is:
import unittest
import importlib
class MyTest(unittest.TestCase):
def setUp(self):
pass
def test_power_3_4(self):
self.assertEqual(module.powerFunction(2, 3), 8)
files = ['submission1', 'submission2', 'submission3']
for file in files:
module = importlib.import_module(file)
print module
unittest.main()
if the test code is run the console output shows only submission1 being tested:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
/Users/staff/PycharmProjects/UnitTest/powerTest.py
<module 'submission1' from '/Users/staff/PycharmProjects/UnitTest/
submission1.pyc'>
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Process finished with exit code 0
Interestingly if I don't use unit testing I can correctly import and test using this approach:
import importlib
files = ['submission1', 'submission2', 'submission3']
for file in files:
module = importlib.import_module(file)
print module
print module.powerFunction(2,3)
The console output here is:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/
python2.7 /Users/staff/PycharmProjects/UnitTest/importlib1.py
<module 'submission1' from '/Users/staff/PycharmProjects/UnitTest/
submission1.pyc'>
8.0
<module 'submission2' from '/Users/staff/PycharmProjects/UnitTest/
submission2.pyc'>
8
<module 'submission3' from '/Users/staff/PycharmProjects/UnitTest/
submission3.pyc'>
8
Process finished with exit code 0
It may well be that the unittest module is not the best approach here but I'm still interested on how to implement it.
You can use importlib to load Python modules from specific files, then run the test cases on each one.
glob may be helpful to create the list of files.
Given that this has been active for a month with no answers I have come the the realisation that it is because I'm asking for the wrong thing.
From what I can gather, unittest is for running a suite of tests on a single application. It is not designed to run a single test on a suite of applications.
John's suggestion to investigate importlib helped set me on the path to success. Thanks John.
The code posted in the original post update seems to be the most appropriate solution to my problem.

python Unitest sample Application

I am facing problem in Python Unittesting,
simple Addition of two numbers in python Unitest, for different test case ID or Different Inputs.
-------Prasanna Yelsangikar
import unittest
class UnitTestExamples(unittest.TestCase):
def testsum(self):
a = 10
b = 42
self.assertEqual(a+b,52)
if __name__ == '__main__':
unittest.main()
Run the above in with your python interpretor using -v flag.
python testexample.py -v
And you will see that testsum is run and the test is exercised. unittest documentation has details how the working and the above example should be simple enough to get you started. The methods which start with the name test are run by the unittest framework.
#test_numbers.py is located at 'tests' folder
import unittest
class testNumbers(unittest.TestCase):
def test_add_two_numbers(self):
first_number = 3
second_number = 7
result = first_number + second_number
expected = 10
self.assertEqual(result,expected)
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(testNumbers)
unittest.TextTestRunner(verbosity=3).run(suite)
run on terminal :
python -m tests.test_numbers

Categories

Resources