Getting nose to ignore a function with 'test' in the name - python

The nose discovery process finds all modules whose name starts with test, and within them all functions which have test in the name and tries to run them as unit tests. See http://nose.readthedocs.org/en/latest/man.html
I have a function whose name is say, make_test_account, in the file accounts.py. I want to test that function in a test module called test_account. So at the start of that file I do:
from foo.accounts import make_test_account
But now I find that nose treats the function make_test_account as a unit test and tries to run it (which fails because it doesn't pass in any parameters, which are required).
How can I make sure nose ignores that function specifically? I would prefer to do it in a way which means I can invoke nose as nosetests, without any command line arguments.

Tell nose that the function is not a test - use the nottest decorator.
# module foo.accounts
from nose.tools import nottest
#nottest
def make_test_account():
...

Nose has a nottest decorator. However, if you don't want to apply the #nottest decorator in the module you are importing from you can also simply modify the method after the import. It may be cleaner to keep unit test logic close to the unit test itself.
from foo.accounts import make_test_account
# prevent nose test from running this imported method
make_test_account.__test__ = False
You can still use nottest but it has the same effect:
from nose.tools import nottest
from foo.accounts import make_test_account
# prevent nose test from running this imported method
make_test_account = nottest(make_test_account)

Related

Python Unit testing script that calls some functions

I ended up with testing an "automation" script in python, basically just a script calling bunch of functions.
I have 3 classes: class_A, class_B, class_C, with each class having a "run" function
Script.py is calling class_A.run(), class_B.run, class_C.run()
My question would be if is there is a way of unit testing Script.py to just assert if the 3 run functions we're called, without actually running (going trough their code) them.
I tried patching the class and i can get the correct assert, but the run functions are still "running" their code.
Is it possible to somehow Mock the class_A.run() and assert if was called?
You could use Mock patch.
The MockClass will replace your module.class_A and the run-method:
from unittest.mock import patch
#patch('module.class_A', 'run')
def test(MockClass):
Script.py # your testfunction
assert MockClass.run.called # check if module.Class_A.run() was called

Testing a pytest fixture [duplicate]

What is the proper way to test that the pytest fixture itself. Please do not confuse it with using fixture in tests. I want just tests the fixtures correctness by itself.
When trying to call and execute them inside test I am facing:
Fixture "app" called directly. Fixtures are not meant to be called directly
Any input on that will be appreciated. Docs on this topic are not giving me meaningful guidance: https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly
The motivation for testing fixtures itself come to me, because when our test were failing due to bug in fixture this wasn't tracked correctly in our TAP files, what motivated me to test the fixtures stand alone.
pytest has a pytester plugin that was made for the purpose of testing pytest itself and plugins; it executes tests in an isolated run that doesn't affect the current test run. Example:
# conftest.py
import pytest
pytest_plugins = ['pytester']
#pytest.fixture
def spam(request):
yield request.param
The fixture spam has an issue that it will only work with parametrized tests; once it is requested in an unparametrized test, it will raise an AttributeError. This means that we can't test it via a regular test like this:
def test_spam_no_params(spam):
# too late to verify anything - spam already raised in test setup!
# In fact, the body of this test won't be executed at all.
pass
Instead, we execute the test in an isolated test run using the testdir fixture which is provided by the pytester plugin:
import pathlib
import pytest
# an example on how to load the code from the actual test suite
#pytest.fixture
def read_conftest(request):
return pathlib.Path(request.config.rootdir, 'conftest.py').read_text()
def test_spam_fixture(testdir, read_conftest):
# you can create a test suite by providing file contents in different ways, e.g.
testdir.makeconftest(read_conftest)
testdir.makepyfile(
"""
import pytest
#pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
""")
result = testdir.runpytest()
# we should have two passed tests and one failed (unarametrized one)
result.assert_outcomes(passed=2, errors=1)
# if we have to, we can analyze the output made by pytest
assert "AttributeError: 'SubRequest' object has no attribute 'param'" in ' '.join(result.outlines)
Another handy possibility of loading test code for the tests is the testdir.copy_example method. Setup the root path in the pytest.ini, for example:
[pytest]
pytester_example_dir = samples_for_fixture_tests
norecursedirs = samples_for_fixture_tests
Now create the file samples_for_fixture_tests/test_spam_fixture/test_x.py with the contents:
import pytest
#pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
(it's the same code that was passed as string to testdir.makepyfile before). The above test changes to:
def test_spam_fixture(testdir, read_conftest):
testdir.makeconftest(read_conftest)
# pytest will now copy everything from samples_for_fixture_tests/test_spam_fixture
testdir.copy_example()
testdir.runpytest().assert_outcomes(passed=2, errors=1)
This way, you don't have to maintain Python code as string in tests and can also reuse existing test modules by running them with pytester. You can also configure test data roots via the pytester_example_path mark:
#pytest.mark.pytester_example_path('fizz')
def test_fizz(testdir):
testdir.copy_example('buzz.txt')
will look for the file fizz/buzz.txt relative to the project root dir.
For more examples, definitely check out the section Testing plugins in pytest docs; also, you may find my other answer to the question How can I test if a pytest fixture raises an exception? helpful as it contains yet another working example to the topic. I have also found it very helpful to study the Testdir code directly as sadly pytest doesn't provide an extensive docs for it, but the code is pretty much self-documenting.

How to test the pytest fixture itself?

What is the proper way to test that the pytest fixture itself. Please do not confuse it with using fixture in tests. I want just tests the fixtures correctness by itself.
When trying to call and execute them inside test I am facing:
Fixture "app" called directly. Fixtures are not meant to be called directly
Any input on that will be appreciated. Docs on this topic are not giving me meaningful guidance: https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly
The motivation for testing fixtures itself come to me, because when our test were failing due to bug in fixture this wasn't tracked correctly in our TAP files, what motivated me to test the fixtures stand alone.
pytest has a pytester plugin that was made for the purpose of testing pytest itself and plugins; it executes tests in an isolated run that doesn't affect the current test run. Example:
# conftest.py
import pytest
pytest_plugins = ['pytester']
#pytest.fixture
def spam(request):
yield request.param
The fixture spam has an issue that it will only work with parametrized tests; once it is requested in an unparametrized test, it will raise an AttributeError. This means that we can't test it via a regular test like this:
def test_spam_no_params(spam):
# too late to verify anything - spam already raised in test setup!
# In fact, the body of this test won't be executed at all.
pass
Instead, we execute the test in an isolated test run using the testdir fixture which is provided by the pytester plugin:
import pathlib
import pytest
# an example on how to load the code from the actual test suite
#pytest.fixture
def read_conftest(request):
return pathlib.Path(request.config.rootdir, 'conftest.py').read_text()
def test_spam_fixture(testdir, read_conftest):
# you can create a test suite by providing file contents in different ways, e.g.
testdir.makeconftest(read_conftest)
testdir.makepyfile(
"""
import pytest
#pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
""")
result = testdir.runpytest()
# we should have two passed tests and one failed (unarametrized one)
result.assert_outcomes(passed=2, errors=1)
# if we have to, we can analyze the output made by pytest
assert "AttributeError: 'SubRequest' object has no attribute 'param'" in ' '.join(result.outlines)
Another handy possibility of loading test code for the tests is the testdir.copy_example method. Setup the root path in the pytest.ini, for example:
[pytest]
pytester_example_dir = samples_for_fixture_tests
norecursedirs = samples_for_fixture_tests
Now create the file samples_for_fixture_tests/test_spam_fixture/test_x.py with the contents:
import pytest
#pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
(it's the same code that was passed as string to testdir.makepyfile before). The above test changes to:
def test_spam_fixture(testdir, read_conftest):
testdir.makeconftest(read_conftest)
# pytest will now copy everything from samples_for_fixture_tests/test_spam_fixture
testdir.copy_example()
testdir.runpytest().assert_outcomes(passed=2, errors=1)
This way, you don't have to maintain Python code as string in tests and can also reuse existing test modules by running them with pytester. You can also configure test data roots via the pytester_example_path mark:
#pytest.mark.pytester_example_path('fizz')
def test_fizz(testdir):
testdir.copy_example('buzz.txt')
will look for the file fizz/buzz.txt relative to the project root dir.
For more examples, definitely check out the section Testing plugins in pytest docs; also, you may find my other answer to the question How can I test if a pytest fixture raises an exception? helpful as it contains yet another working example to the topic. I have also found it very helpful to study the Testdir code directly as sadly pytest doesn't provide an extensive docs for it, but the code is pretty much self-documenting.

Unable to mock a function in Python (Django)

I'm trying to mock a function used within the function I'm testing, but for some reason I'm not seeing the original function always runs, not the one I created as a mock.
The code I'm testing has this type of setup:
def function_being_tested(foo):
...
function_i_want_to_mock(bar)
...
def function_i_want_to_mock(bar)
print("Inside original function")
...
I've installed Mock and I've tried using unittest.mock patch
Currently the test file uses this setup:
import mock
from django.test import TestCase
def mock_function_i_want_to_mock(bar):
print(bar)
return True
class SupportFunctionsTestCases(TestCase):
#mock.patch("path.to.function.function_i_want_to_mock", mock_function_i_want_to_mock)
def test_function_being_tested(self):
# setup
result = function_being_tested(test_foo)
self.assertEqual(result, expected_result)
What then happens is when I run the test, I always get: "Inside original function", not the parameter printed so it's always running the original function.
I've used this exact setup before and it has worked so I'm not sure what's causing this. Probably some wrong setup...
If anyone has a different way of doing this or spots some error, it would be appreciated.
"path.to.function.function_i_want_to_mock" should be a path to where the function is used, not defined.
So if function_i_want_to_mock is defined in moduleA.py but imported and used in moduleB.py which you are testing then you should use #mock.patch("path.to.moduleB.function_i_want_to_mock", ...).

How to define a setup method only called once during testing with nosetest?

I am running a couple of nosetests with test cases in different modules (files) each containing different tests.
I want to define a function/method that is only called once during the execution with nosetest.
I looked at the documentation (and e.g. here) and see there are methods like setup_module etc. - but where and how to use them? Put them into my __init__.py? Something else?
I tried to use the following:
class TestSuite(basicsuite.BasicSuite):
def setup_module(self):
print("MODULE")
...
but this printout is never done when I run the test with nosetest. I also do not derive from unittest.TestCase (which will result in errors).
When looking at a package level, you can define a function named setup in the __init__.py of that package. Calling the tests in this package, the setup function in the __init__.py is called once.
Example setup
- package
- __init__.py
- test1.py
- test2.py
See documentation section 'Test packages'.
Try this one
from nose import with_setup
def my_setup_function():
print ("my_setup_function")
def my_teardown_function():
print ("my_teardown_function")
#with_setup(my_setup_function, my_teardown_function)
def test_my_cool_test():
assert my_function() == 'expected_result'
Holp it helps ^^

Categories

Resources