I'm working on the Code-dojo Tennis Kata and I'm stuck with the silliest problem. My pytest stops after running the first test in the file. My test file looks like this:
from tennis import game
import re
def test_game_start(capsys):
MaxVsMimi = game()
MaxVsMimi.result()
out, err = capsys.readouterr()
assert bool(re.search(r'Love : Love', out))
def p1_scores_once(capsys):
MaxVsMimi = game()
MaxVsMimi.score("p1")
MaxVsMimi.result()
out, err = capsys.readouterr()
assert bool(re.match(r'^abc', out))
This is the code:
class game:
def __init__(self):
self.scorep1 = "Love"
self.scorep2 = "Love"
def result(self):
print(self.scorep1, ":", self.scorep2)
and the output:
:stdout:
============================= test session starts ==============================
platform linux -- Python 3.8.6, pytest-6.0.2, py-1.9.0, pluggy-0.13.1 -- /usr/local/bin/python
cachedir: .pytest_cache
rootdir: /sandbox
collecting ... collected 1 item
test_tennis.py::test_game_start PASSED [100%]
============================== 1 passed in 0.01s ===============================
Why does it not run the second "p1_scores_once" test?
Thanks!
Pytest, like many testing libraries including unittest require all test functions to have the word test in the start of the name. You can fix your code simply by changing the name of p1_scores_once:
def test_p1_scores_once(capsys):
...
Now the automatic test-finding system will treat the function like a test case.
Related
I am trying to check the exit code I have for a script I'm writing in python3 on a Mac (10.14.4). When I run the test it doesn't fail which I think is wrong. But I can't see what it is that I've got wrong.
The test file looks like this:
import pytest
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import my_script
class TestMyScript():
def test_exit(self):
with pytest.raises(SystemExit) as pytest_wrapped_e:
my_script.main()
assert pytest_wrapped_e.type == SystemExit
def test_exit_code(self):
with pytest.raises(SystemExit) as pytest_wrapped_e:
my_script.main()
self.assertEqual(pytest_wrapped_e.exception.code, 42)
My script looks like:
#!/usr/bin/env python3
import sys
def main():
print('Hello World!')
sys.exit(0)
if __name__ == '__main__':
main()
The output I get is:
$ py.test -v
============================= test session starts ==============================
platform darwin -- Python 3.7.3, pytest-3.10.1, py-1.8.0, pluggy-0.9.0 -- /usr/local/opt/python/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/robertpostill/software/gateway, inifile:
plugins: shutil-1.6.0
collected 2 items
test/test_git_refresh.py::TestGitRefresh::test_exit PASSED [ 50%]
test/test_git_refresh.py::TestGitRefresh::test_exit_code PASSED [100%]
=========================== 2 passed in 0.02 seconds ===========================
$
I would expect the second test(test_exit_code) to fail as the exit call is getting a code of 0, not 42. But for some reason, the assert is happy whatever value I put in the sys.exit call.
Good question, that's because your Asserts are never called (either of them). When exit() is called the program is done (at least within the with clause), it turns off the lights, packs up its bags, and goes home. No further functions will be called. To see this add an assert before and after you call main:
def test_exit_code(self):
with pytest.raises(SystemExit) as pytest_wrapped_e:
self.assertEqual(0, 1) # This will make it fail
my_script.main()
self.assertEqual(0, 1) # This will never be called because main `exits`
self.assertEqual(pytest_wrapped_e.exception.code, 42)
A test passes if no asserts fail and nothing breaks, so in your case both tests passed because the assert was never hit.
To fix this pull your asserts out of the with statement:
def test_exit_code(self):
with pytest.raises(SystemExit) as pytest_wrapped_e:
my_script.main()
self.assertEqual(pytest_wrapped_e.exception.code, 42)
Though now you will need to fix the pytest syntax because you are missing some other stuff.
See: Testing sys.exit() with pytest
I am trying to run a pytest on eclipse for the below code:
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
Expected result got displayed on the console. But with an error: pydev test runner error: imported unittest before running pytest.main.
Please let me know how can I remove this error
Entire result is:
pydev test runner error: imported unittest before running pytest.main
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-3.6.0, py-1.5.3, pluggy-0.6.0
rootdir: D:\Eclipse1\TFCProject, inifile:
collected 1 item
TFCPackage\pycheck.py F [100%]
================================== FAILURES ===================================
_________________________________ test_answer _________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
TFCPackage\pycheck.py:10: AssertionError
========================== 1 failed in 0.35 seconds ===========================
This is already fixed in github/master.
The problem is that pydev checked that it did not inadvertently import unittest when using the pytest runner and gave that message when that happened, but recently pytest itself started to import unittest internally (thus making the behavior that pydev tried to prevent something that always happens by default).
So, the next release should have that fixed (6.3.4).
I am trying to run pytest from within python after running a thread,
here is a simple example of the case:
import time
import threading
import pytest
class A(object):
def __init__(self):
self._thread_a = threading.Thread(target=self.do_a)
self._thread_a.start()
pytest.main()
def do_a(self):
print "a"
time.sleep(2)
self.do_a()
if __name__ == "__main__":
a = A()
but pytest keeps hanging. this is what the output looks like:
============================= test session starts ==============================
platform darwin -- Python 2.7.10, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
metadata: {'Python': '2.7.10', 'Platform': 'Darwin-17.3.0-x86_64-i386-64bit', 'Packages': {'py': '1.5.2', 'pytest': '3.3.2', 'pluggy': '0.6.0'}, 'Plugins': {'session2file': '0.1.9', 'celery': '4.0.0','html': '1.16.1', 'metadata': '1.5.1'}}
rootdir: /Users/path/to/root/dir, inifile:
plugins: session2file-0.1.9, metadata-1.5.1, html-1.16.1, celery-4.0.0
and it just hangs like this until I force quit it.
is there any way to make this work?
Two things to mention:
you possibly want to stop the thread if you code is done with something.
you may also separate your code from the test code.
Lets say:
file.py
import time
import threading
class A(object):
def __init__(self):
self._thread_a = threading.Thread(target=self.do_a)
self._thread_a.daemon = True
self._thread_a.start()
def do_a(self):
print "a"
time.sleep(2)
self.do_a()
def stop(self, timeout):
self._thread_a.join(timeout)
test_file.py
import pytest
from .file import A
#pytest.fixture()
def a():
return A()
def test_sth(a):
a.start()
print('I can do sth else')
a.stop(timeout=1)
I try to collect my tests with py.test but it doesn't do so.
Do I have to provide additional options at the command line?
Py.test was executed in the directory of my .py-file. Are there any other requirements?
Are my tests named correctly? In my code I used 'Test-' for classes and 'test_' for methods.
The results from the terminal:
> py.test
=============================== in 0.00 seconds ============================
user#host:~/workspace/my_project/src/html_extractor$ py.test
============================= test session starts ===========================
platform linux2 -- Python 2.7.3 -- pytest-2.3.4
plugins: xdist
collected 0 items
My code under test:
class Factories(object):
TEST_LINKS = ['http://www.burgtheater.at',
'http://www.musikverein.at/']
def links(self):
for link in self.TEST_LINKS:
yield link
class TestHTMLExtractor(unittest.TestCase):
def setUp(self):
self.factory = Factories()
self.extractor = HTMLExtractor()
def test_extract_site_return(self):
for link in self.factory.links():
raw_html_page = self.extractor.run(link)
def test_whatever():
pass
if __name__ == '__main__':
unittest.main()
In the default configuration, the test file should be named test_<something>.py. See Changing standard (Python) test discovery.
I am using py.test to write some tests and in my tests I utilize funcargs. These funcargs have their own setups and teardowns defined in the conftest.py like this:
conftest.py:
def pytest_funcarg__resource_name(request):
def setup():
# do setup
def teardown():
# do teardown
My problem is when someone uses CTRL+C to stop the test executions it leaves everything un-teardowned.
I know there is a hook pytest_keyboard_interrupt but I dont know what to do from there.
Sorry for the noobish question.
You don't provide a full example so maybe i am missing something. But here is an example of how it can work, using the request.cached_setup() helper:
def pytest_funcarg__res(request):
def setup():
print "res-setup"
def teardown(val):
print "res-teardown"
return request.cached_setup(setup, teardown)
def test_hello(res):
raise KeyboardInterrupt()
If you run this with "py.test" you get:
============================= test session starts ==============================
platform linux2 -- Python 2.7.3 -- pytest-2.2.5.dev4
plugins: xdist, bugzilla, pep8, cache
collected 1 items
tmp/test_keyboardinterrupt.py res-setup
res-teardown
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/home/hpk/p/pytest/tmp/test_keyboardinterrupt.py:10: KeyboardInterrupt
which shows that setup and teardown are called if a KeyboardInterrupt occurs during test execution.