How to isolate pytest tests - pytest

I'm running a test with class fixture, and how to make test_b and test_c to be isolated, such that both started with a_list = ['a'] only.
I know changing the fixture scope to function would achieve what I asked. But the fixture have to be class scoped. Is there some way to tell test_b and test_c to take a snapshot of a_list before running?
#pytest.fixture(scope="class")
def a_list(self):
return ['a']
def test_b(self,a_list):
a_list.append('b')
assert a_list == ['a','b']
def test_c(self,a_list):
assert a_list == ['a','b']

You can work on a copy of a_list in each test you want to modify it
#pytest.fixture(scope="class")
def a_list(self):
return ['a']
def test_b(self, a_list):
a_list = a_list[:]
a_list.append('b')
assert a_list == ['a', 'b']
def test_c(self, a_list):
assert a_list == ['a', 'b']
Output
PASSED [ 50%]
FAILED [100%]
example_test.py:31 (Test.test_c)
['a'] != ['a', 'b']
Expected :['a', 'b']
Actual :['a']
<Click to see difference>
self = <example_test.Test object at 0x0000011696077A90>, a_list = ['a']
def test_c(self, a_list):
> assert a_list == ['a', 'b']
E AssertionError: assert ['a'] == ['a', 'b']
example_test.py:35: AssertionError

Related

How to use multiple pytest fixtures with same parameterized input to test methods in a class

I want to achieve something like this:
my conftest.py will contain:
fixture_1 - will do some manipulation with input such as a, b, c using request.param
fixture_2 - will do some manipulation with input such as a, b, c using request.param
fixture_3 - will do some manipulation with input such as a, b, c using request.param
#pytest.mark.parametrize('param_name', ['a', 'b', 'c'], indirect=True)
class TestDummy(object):
def test_x(self, fixture_1):
fixture_1_output = fixture_1
assert False
def test_y(self, fixture_2):
fixture_2_output = fixture_2
assert False
def test_z(self, fixture_3):
fixture_3_output = fixture_3
assert False
Any suggestion would be highly appreciated.
You cannot directly patameterize the fixture name this way. Either you use parametrize for each test separately:
def params():
return ['a', 'b', 'c']
class TestDummy:
#pytest.parametrize(fixture_1, params, indirect=True)
def test_x(self, fixture_1):
fixture_1_output = fixture_1
assert False
#pytest.parametrize(fixture_2, params, indirect=True)
def test_y(self, fixture_2):
fixture_2_output = fixture_2
assert False
#pytest.parametrize(fixture_3, params, indirect=True)
def test_z(self, fixture_3):
fixture_3_output = fixture_3
assert False
(I moved the parameters into an extra function for convenience)
Or you have to do the parametrization dynamically based on the fixture name using pytest_generate_tests:
def pytest_generate_tests(metafunc):
fixtures = [f for f in metafunc.fixturenames if f.startswith("fixture_")]
if len(fixtures) == 1:
metafunc.parametrize(fixtures[0], ['a', 'b', 'c'], indirect=True)
class TestDummy:
def test_x(self, fixture_1):
fixture_1_output = fixture_1
assert False
def test_y(self, fixture_2):
fixture_2_output = fixture_2
assert False
def test_z(self, fixture_3):
fixture_3_output = fixture_3
assert False
def test_something_else(self):
pass
You need to determine which tests to parametrize - in this example all tests are parametrized which have exactly one fixture with a name starting with "fixture_", you may have to adapt ths to your needs.
In this example, the first 3 tests will be parametrized, but not the last one (test_something_else).

How to compare two arrays and find the indices where the elements differ?

Is there any builtin function in Scala (not able to fetch indexes after comparing)?
Here is some JavaScript code I already have:
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = arrayDiff(newTags, oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b'] "
You can do it really easy using zipWithIndex, and unzip
val (diffValues, diffIndexes) = newTags.zipWithIndex.filter(c => !oldTags.contains(c._1)).unzip
Code run at Scastie
You can do something as follows:
def arrayDiff[T](newTags: List[T], oldTags: List[T]) = {
oldTags.foldLeft(newTags.zipWithIndex.toMap) {
case (seed, char) => {
seed.get(char) match {
case Some(_) => seed - char
case _ => seed
}
}
}
}
val newTags = List('a', 'b', 'c')
val oldTags = List('c')
val (diffIndexes, diffValues) = arrayDiff(newTags, oldTags).unzip
println(diffIndexes) // List(a, b)
println(diffValues) // List(0, 1)
I'm not sure if that what you meant, since what you want to do when oldTags has some values that newTags not?, In my case scenario - its will ignore the oldTag since its not in the newTags

How to add test-specific user properties to report with pytest-reportlog?

Say I have a test
# contents of test_foo.py
import pytest
#pytest.mark.parametrize("value,expected", [(2, 4), (4, 16)])
def test_square(value: int, expected: int):
assert value**2 == expected
and I want to return a JSON report of the test with pytest-reportlog. How can I add data to the report in each test? Specifically, I would like to add the value of value and expected to the report for each test.
I run the tests with
pytest --report-log report.json
and I have pytest==6.2.1 and pytest-reportlog==0.1.2 installed.
Use the record_property fixture (see examples). This fixture allows you to use a callable with the signature record_property(name: str, value: object) -> None
import typing as ty
import pytest
#pytest.mark.parametrize("value,expected", [(2, 4), (4, 16)])
def test_square(
record_property: ty.Callable[[str, ty.Any], None], value: int, expected: int
):
record_property("value", value)
record_property("expected", expected)
assert value**2 == expected
These values can be access in the user_properties key of the JSON objects for these tests.
For example:
"user_properties": [["value", 2], ["expected", 4]]

How to xfail off a conditional involving a parametrization?

How to xfail off a conditional involving a parametrization?
The issue is that #pytest.mark.xfail(condition=(code == 123), reason="123 is an exception case") doesn't work because code is a parametrized variable. I tried some different things including static class members, globals, and setting it in the expected_setup fixture. None of these worked (as expected)
#pytest.mark.xfail(condition=(code == 123), reason="123 is an exception case")
E NameError: name 'code' is not defined
params = [
cls1,
cls2,
cls3,
cls4
]
#pytest.mark.parametrize('code', params, ids=list(map(str, params)))
class TestContextExit(object):
#pytest.fixture(autouse=True)
def expected_setup(self, code):
self.str1 = 'JETFUEL'
self.str2 = 'OPERATIONNORTHWOODS'
self.setup = NewStore(self.str1, self.str2, code)
def test1(self, code):
assert self.root.results.result_code == expected_result_code
assert self.root.results.ta['result_code'] == expected_result_code.code
assert self.root.results.result_code == expected_result_code
#pytest.mark.xfail(condition=(code == 123), reason="123 is an exception case")
def test2(self, code):
assert self.setup.root['code'] == code
#pytest.mark.xfail(condition=(code == 123), reason="123 is an exception case")
def test3(self, code):
assert self.setup.root['setup'] == NOERROR
Any ideas or patterns? Looking at the xfail pytest docs, I don't see any examples xfailing off parametrizations, except for the as part of the params. But in this case, the class is being parametrized and only two of the class tests turn into xfails, not all the tests.
You can use pytest.param with xfail mark as a param value in parametrization to xfail a param.
#pytest.mark.parametrize(code, [1,pytest.param(0,marks=pytest.mark.xfail(reason="reasons")]
def test_a():
assert code
This is used to mark certain parametrization value. This will xfail 2nd test.

How to set a list of pytest markers to a test?

I am using 2 markers '#pytest.mark.regression' and '#pytest.mark.smoke'. I need all my tests to have these 2 markers, so I wanted to create a list like
allmarkersList = [pytest.mark.regression, pytest.mark.smoke] and I want to call this marker #allmarkersList to all my tests, is this possible ?
import pytest
allmarkers = [pytest.mark.regression, pytest.mark.smoke]
#pytest.mark.regression
def test_reg1():
assert True
#pytest.mark.regression
def test_reg2():
assert True
#pytest.mark.smoke
def test_smoke1():
assert True
#pytest.mark.smoke
def test_smoke2():
assert True
#allmarkers
def test_reg_and_smoke():
print(all_marks)
assert True
when I run this I get the below error -
#allmarkers
E TypeError: 'list' object is not callable