If I use the mailoutbox fixture like this, it works:
def test_send_invoices_via_mail_page(user_client, invoice, mailoutbox):
url = reverse(send_invoices_via_mail_page)
response = user_client.get(url)
assert response.status_code == 200
log = LogOfInvoiceMail.objects.get(invoice=invoice)
assert log.success, log.exception
assert log.invoice == invoice
assert log.exception == ''
assert len(mailoutbox) == 1, mailoutbox
But if I use it like this it fails:
def test_send_invoices_via_mail_page(mailoutbox, user_client, invoice):
Error:
> assert len(mailoutbox) == 1, mailoutbox
E AssertionError: []
E assert 0 == 1
Why is the order of the arguments important here?
I am 100% sure that mail.send_mail() gets called in both cases, since I tested it ten times (with ten different ways).
Related
I have tests on a function that uses and modifies global variables. I would like to make sure that my global variable is reset between my tests. Any trick to do that?
main.py:
y = 0
def inc(x):
# side effect
global y
y = y + 1
return x + y + 1
test_main.py:
from main import inc
def test_answer():
assert inc(3) == 5
def test_answer_again():
assert inc(3) == 5
_________________________________________________________________________________________ test_answer_again __________________________________________________________________________________________
def test_answer_again():
> assert inc(3) == 5
E assert 6 == 5
E + where 6 = inc(3)
test_main.py:8: AssertionError
====================================================================================== short test summary info =======================================================================================
FAILED test_main.py::test_answer_again - assert 6 == 5
==================================================================================== 1 failed, 1 passed in 0.01s =====================================================================================
Here is how you can use a simple fixture to ensure that the value of y is unchanged after each test:
import pytest
import main
from main import inc
#pytest.fixture
def set_y(request):
y_before = main.y
y_value_to_set = getattr(request, 'param', y_before) # optional parameter
main.y = y_value_to_set
yield # allows us to have cleanup after the test
main.y = y_before # once test is done, revert value for next test
def test_answer(set_y):
assert inc(3) == 5
def test_answer_again(set_y):
assert inc(3) == 5
#pytest.mark.parametrize('set_y', [20], indirect=["set_y"])
def test_answer_with_specific_y(set_y):
assert inc(3) == 25
You can also add the autouse=True to your fixture if you want to prevent the need to specifically mention the fixture in every test and prevent bugs due to missing to specify it:
import pytest
import main
from main import inc
#pytest.fixture(autouse=True)
def set_y(request):
y_before = main.y
y_value_to_set = getattr(request, 'param', y_before) # optional parameter
main.y = y_value_to_set
yield # allows us to have cleanup after the test
main.y = y_before # once test is done, revert value for next test
def test_answer():
assert inc(3) == 5
def test_answer_again():
assert inc(3) == 5
#pytest.mark.parametrize('set_y', [20], indirect=["set_y"])
def test_answer_with_specific_y():
assert inc(3) == 25
If the second parameter of assert is used normally it prints it out debug information.
E.g. with the following code:
class TestTest:
def test_test(self):
assert 1 == 2, "TEST"
The following debug information is printed:
tests\test_test.py:1 (TestTest.test_test)
1 != 2
Expected :2
Actual :1
<Click to see difference>
self = <tests.test_test.TestTest object at 0x000002147E5B1B08>
def test_test(self):
> assert 1 == 2, "TEST"
E AssertionError: TEST
E assert 1 == 2
E +1
E -2
test_test.py:3: AssertionError
However, if the assert happens in a helper function, this is not printed:
class TestTest:
def test_test(self):
self.verify(1)
def verify(self, parameter):
assert 1 == 2, "TEST"
results in:
tests\test_test.py:1 (TestTest.test_test)
1 != 2
Expected :2
Actual :1
<Click to see difference>
self = <tests.test_test.TestTest object at 0x000002AFDF1D5AC8>
def test_test(self):
> self.verify(1)
test_test.py:3:
So the stack trace is incomplete and the debug information not shown.
UPDATE:
This only happens when starting the test through PyCharm (2021.3).
Is there any way to fix this?
How do I ensure that the parameters to this function must be of the set type?
I tried using the isinstance method placed in an assert statement to validate that the remaining and the used parmeters are set types only, but this failed.
def listAllSubset(remaining = set(), used = set()):
assert(isinstance(remaining, set))
assert(isinstance(used, set))
if (len(remaining) == 0):
print(used)
else:
element = remaining.pop()
listAllSubset(remaining, used)
listAllSubset(remaining, used.add(element))
I would like to see how to ensure that the remaining and used parameters are sets only.
Not an efficient way, but a tricky way:
def listAllSubset(remaining = set(), used = set()):
remaining.discard
used.discard
...
the isinstance is Authoritative, the point is in your last line of the code,
this is code
def listAllSubset(remaining = set(), used = set()):
assert(isinstance(remaining, set))
assert(isinstance(used, set))
if (len(remaining) == 0):
print(used)
else:
element = remaining.pop() # OK: element will be None
listAllSubset(remaining, used) # OK: remaining == used == set()
listAllSubset(remaining, used.add(element)) # Error: used.add(element) will return None, and the None will give to keyword argument "used", then "assert" will raise a AssertionError.
if __name__ == "__main__":
listAllSubset()
ok,
Last line code listAllSubset(remaining, used.add(element)) as equal listAllSubset(set(), None),
then assert(isinstance(used, set)) will raise a AssertionError
just look this code
used = set()
flag = used.add('_')
print(flag) # print value of flag
None
changed
I change the code, mybe it can meet your needs,
def listAllSubset(remaining = set(), used = set()):
assert(isinstance(remaining, set))
assert(isinstance(used, set))
if (len(remaining) == 0):
print(used)
else:
element = remaining.pop()
listAllSubset(remaining, used)
used.add(element)
listAllSubset(remaining, used)
please forgive me for my bad English, English is so hard!!
pytest never fails regardless of the assertions being done in first method. The same behavior is observed when I change the order of methods also. It fails only if I change something in the last method's assertions.
from cpu import CPU
#pytest.fixture
def cpu():
return CPU()
def test_00e0(cpu):
cpu.sp = 0xa
cpu.stack[cpu.sp] = 0x220
cpu.pc = 0x200
cpu.i_00ee()
assert cpu.sp == 0x9
assert cpu.pc == 0x220
def test_00e0(cpu):
cpu.display[0][0] = 1
cpu.i_00e0()
assert sum([sum(x) for x in cpu.display]) == 0
assert cpu.draw_flag == True```
Both your test methods have the same name, so the 2nd is overwriting the 1st. Give them different names and you should be OK.
I'm using pytest and have multiple tests to run to check an issue.
I would like to split all tests into different functions like this:
# test_myTestSuite.py
#pytest.mark.issue(123)
class MyTestSuite():
def test_part_1():
result = do_something()
assert result == True
def test_part_2():
result = do_an_other_something()
assert result == 'ok'
of course, I implemented issue in conftest.py
# conftest.py
def pytest_addoption(parser):
group = parser.getgroup('Issues')
group.addoption('--issue', action='store',
dest='issue', default=0,
help='')
but I don't know how to hook once after testing MyTestSuite and check that all tests of MyTestSuite correctly passed.
Does anyone have any ideas?
PS: this is my first post on StackOverflow.
Try to use the return function as most simple type of positive debug conformation as shown below.
#pytest.mark.issue(123)
class MyTestSuite():
def test_part_1():
result = do_something()
assert result == True
return 'tp1', True
def test_part_2():
result = do_an_other_something()
assert result == 'ok'
return 'tp2', True
..and then where you run your tests from:
x = MyTestSuite().test_part_1()
if x[1] == True:
print 'Test %s completed correctly' % x[0]
The result after running test1:
Test tp1 completed correctly, or...
AssertionError.
Collecting assertion errors:
collected_errors = []
def test_part_1():
testname = 'tp1'
try:
result = do_something()
assert result == True
return testname, True
except Exception as error:
info = (testname, error)
collected_errors.append(info)
More assertion flavours you can find here on SO.