Can Pytest exclude certain lines of code? - python

I'm using Pytest to run test on one file that goes like this:
def function():...
def test_function():...
def main():...
main()
I want Pytest to exclude the line that calls main, is it possible?

Pytest will execute only those functions with test as a prefix. Since you have already have a function def function() at the start there can be some issues running the entire test case.
As #hoefling commented, pytest can not skip the code.
Try adding the following at the end of you code:
if __name__=='__main__':
main()

Related

#unittest.skip(reason) can't work on main function

I'd like to prevent/skip some tests cases during runinng others in python. I couldn't achive to use #unittest.skip(reason) on my case. It always generates a Script Error in python unittest.
My code;
import unittest
#unittest.skip("something")
def main():
try:
something = []
for _ in range(4):
test.log("something happened")
The result is;
Error Script Error
Detail: SkipTest: something
Do you have any idea about the issue?
Unittest is a module that act as testing framework. You should use it according to the framework practices (taken from tutorialspoint.com):
import unittest
def add(x,y):
return x+y
class SimpleTest(unittest.TestCase):
#unittest.skip("demonstrating skipping")
def testadd1(self):
self.assertEquals(add(4,5),9)
if __name__ == '__main__':
unittest.main()
Squish test scripts written in Python are unrelated to the unittest module. I cannot tell how the two could be used together.
Squish offers the test.skip() function for skipping test cases:
test.skip(message);
test.skip(message, detail);
This function skips further execution of the current script test case, or the current BDD scenario (or BDD scenario outline iteration), by throwing an exception and adding a SKIPPED entry to Squish's test log with the given message string, and with the given detail, if provided. If the test case logged verification failures before the skip, it is still considered failed.

Why doesn't the test work without if __name__ == '__main__'?

I can't figure out why without the line if __name__ == '__main__': before unittest.main() the test does not find?
I am using the latest version of PyCharm. I know that in order for the test to work in PyCharm, you can not add these lines at all, but I want to deal with the logic itself: why without the line if __name__ == '__main__': the result is as in the screenshot, but if you add it, then everything works?
Code:
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""Tests for 'name_function.py'."""
def test_first_last_name(self):
"""Are names like 'Janis Joplin' working correctly?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
unittest.main()
There is only one function in the name_function module:
def get_formatted_name(first, last):
"""Builds a formatted full name."""
full_name = f"{first} {last}"
return full_name.title()
Result:
No tests were found
/Users/xxx/Documents/PycharmProjects/Book/venv/bin/python
"/Applications/PyCharm
CE.app/Contents/plugins/python-ce/helpers/pycharm/_jb_unittest_runner.py"
--path /Users/xxx/Documents/PycharmProjects/Book/testing.py
Testing started at 00:22 ...
-------------------------------------------------------------------> Ran 0 tests in 0.000s
OK
Launching unittests with arguments python -m unittest
/Users/xxx/Documents/PycharmProjects/Book/testing.py in
/Users/xxx/Documents/PycharmProjects/Book
Process finished with exit code 0
Empty suite
Empty suite
I am running the testing.py module as the main program, but judging by the answer line PyCharm is running the test via python -m unittest testing.NamesTestCase
I additionally checked the value of the global variable __name__ and indeed it has the value testing, as if testing was imported. Although I launch it initially.
Please explain why in this case the startup script differs from the standard one and when testing.py starts it runs it through unittest? I really want to finally understand this issue. Also don't understand why, in this case, if it initially runs through unittest, unittest.main() doesn't run normally without additional checking if __name__ == '__main__':?

How to mock out some functions inside a module which I want to be imported?

CAUTION: This situation was happened because of a mistake. Check my answer.
I have a python file (myfile.py) which I want to test its content with Pytest. (The content is changing dynamically)
I've wrote this code:
import importlib
def test_myfile(capsys, monkeypatch):
monkeypatch.setattr('builtins.input', lambda s: "some_input")
# Create a module from the custom Problem file and import it
my_module = importlib.import_module("myfile")
# Rest of the test script
when I run the test I'm getting this error:
OSError: reading from stdin while output is captured
The error has been produced because there is an input() instruction in myfile.py and it means that mocking that function was futile.
My Question:
How can I mock out some functions inside a module I want to import?
Finally I found that I was looking wrong place to find a solution.
actually I use pytest to check a learner response and grade it. this was the way I did that at the moment I asked this question.
py.test test_runner.py test_case.py -v
This will test the user response which is saved in test_case.py ( I get the second parameter inside my test method and load its content and for example run a desired function ). Then I was examining the report of pytest to see if there was an error or failure to decide about the result. (pass/failure)
normally pytest was failing if there was an error in users code (e.g. syntax error) or if the test was failing (e.g. didn't return what it must return)
This time there was an error I didn't want to stop the test. I want to mock out input() function in users code. when I was running the command, before running my test method, pytest imported both files to collect test methods. It was failing to import test_case.py because of the input() function. It was not even reach the line I asked to mock that function and failed in the init stage.
At last to fix the problem I've added a parameter to py.test and now I'm running test process like this:
py.test test_runner.py --program test_case.py -v
In this form pytest doesn't look in test_case.py for test methods and doesn't fail.
hope this experience helps someone else

PyCharm doesn't appear to run all unit tests

I have a problem running unittests in pycharm. The first class 'KnownValues' runs but the other class doesn't get checked at all.
import roman
import unittest
class KnownValues(unittest.TestCase):
def test_too_large(self):
'''to_roman should fail with large input'''
self.assertRaises(roman.OutOfRangeError, roman.to_roman, 4000)
def test_too_small(self):
ls = [0,-1,-25,-60]
for x in ls:
self.assertRaises(roman.OutOfRangeError, roman.to_roman, x)
def test_non_int(self):
ls = [1.5, -6.5, 6.8,12.9, "hello wold", "nigga123"]
for x in ls:
self.assertRaises(roman.TypeError, roman.to_roman, x)
class Test2(unittest.TestCase):
def test1(self):
assert 1 == 1
if __name__ == '__main__':
unittest.main()
Start all of your test functions with test. Many people use underscores to separate words, so a lot of people end up with tests starting with test_, but test is all that is required.
When having trouble in the GUI, you can check how your tests are running from the command line.
python test.py
or
python -m test
One problem that you might run into is that you have defined your tests within classes, and when running them through the GUI, the GUI has automatically discovered them for you. Be sure to include the lines at the end of your test file directing the interpreter to use the main function built into unittest.
if __name__ == '__main__':
unittest.main()
Keep in mind, you can optionally run the tests in only one of your classes at a time:
python tests.py KnownValues
python tests.py Test2
In PyCharm, it should automatically discover all the test classes. You still have the option of running only one class at a time. Choose Run->Edit Configurations to see the options that you are currently running under. Using command line parameters you can control running fewer or more tests.
As you can see, you can choose to run a script, a class, or a method. Be sure to set the name of your run configuration such that it reflects the scope of what you are running.

Pytest: run a function at the end of the tests

I would like to run a function at the end of all the tests.
A kind of global teardown function.
I found an example here and some clues here but it doesn't match my need. It runs the function at the beginning of the tests. I also saw the function pytest_runtest_teardown(), but it is called after each test.
Plus: if the function could be called only if all the tests passed, it would be great.
I found:
def pytest_sessionfinish(session, exitstatus):
""" whole test run finishes. """
exitstatus can be used to define which action to run. pytest docs about this
To run a function at the end of all the tests, use a pytest fixture with a "session" scope. Here is an example:
#pytest.fixture(scope="session", autouse=True)
def cleanup(request):
"""Cleanup a testing directory once we are finished."""
def remove_test_dir():
shutil.rmtree(TESTING_DIR)
request.addfinalizer(remove_test_dir)
The #pytest.fixture(scope="session", autouse=True) bit adds a pytest fixture which will run once every test session (which gets run every time you use pytest). The autouse=True tells pytest to run this fixture automatically (without being called anywhere else).
Within the cleanup function, we define the remove_test_dir and use the request.addfinalizer(remove_test_dir) line to tell pytest to run the remove_test_dir function once it is done (because we set the scope to "session", this will run once the entire testing session is done).
You can use the atexit module. For instance, if you want to report something at the end of all the test you need to add a report funtion as follows:
def report(report_dict=report_dict):
print("THIS IS AFTER TEST...")
for k, v in report_dict.items():
print(f"item for report: {k, v}")
then at the end of the module, you call atexit as follows:
atexit.register(report)
hoop this helps!

Categories