pytest use data from one test as parameter to another test - pytest

I am wondering if it is possible to use data generated from one test as parameter to another test. In my case I need to modify variable (this is list) and it will be great if I can use this list as param (run as many tests as list have)
Here is code (it is not working, but maybe You can give me some hints)
import pytest
class TestCheck:
x = [1, 4]
#classmethod
def setup_class(self):
print('here setup')
#classmethod
def teardown_class(self):
print('here is finish')
def test_5(self):
self.x.append(6)
assert 1 == 2
#pytest.mark.parametrize("region", x)
def test_6(self, region):
assert region > 5, f"x: {self.x}"
Output:
FAILED sandbox_tests3.py::TestCheck::test_5 - assert 1 == 2
FAILED sandbox_tests3.py::TestCheck::test_6[1] - AssertionError: x: [1, 4, 6]
FAILED sandbox_tests3.py::TestCheck::test_6[4] - AssertionError: x: [1, 4, 6]
So it looks that in x there is good values, however in fixture new values are not visible.
I was also trying to use pytest_cases, but results are very similar.
Any help is appreciate

Related

How to assert setup outside teardown in multiply tests

I have a lot of tests, and every test assert something specific, but also assert the setup was done as expected. The setup cannot be verified before the tests starts.
My approach is to assert in the tear-down. Is there a better approach where I do not have to add the assert to every test file, since I have hundredths of them.
Minimal example:
my_test.py
import pytest
#pytest.mark.parametrize("number_a", [1, 2, 3, 4, 5, 6, 7])
def test_low_numbers(number_a):
run_test(number_a=number_a)
def run_test(number_a):
assert number_a != 4
conftest.py
def very_important_check(number_a):
assert number_a != 2, "Not two, stupid."
#pytest.fixture(autouse=True, scope="function")
def signal_handler(request, number_a):
print("########Setup")
yield
print("########Teardown")
very_important_check(number_a)

pytest mock patch side_effect not iterate when used together with pytest.mark.parametrize

I have the below pytest script and the side_effect value [2, 6] is not getting iterated. It is always stuck with value 2 in the test function test_my_function.
My question is:
How to make the side_effect value iterate together with parametrize test cases in function test_my_function. (assume we must use parametrize).
#!/usr/bin/env python3
#
import pytest
def my_function(x):
return x*2
#pytest.fixture
def mock_my_function(mocker):
mocker.patch(
__name__ + ".my_function", side_effect=[2, 6]
)
#pytest.mark.parametrize("input, expect", [(1, 2), (3, 6)])
def test_my_function(input, expect, mock_my_function):
assert expect == my_function(input)
first, your test isn't really testing anything if you mock the function you're trying to test
second, function-scoped fixtures are set up each time the test function is called -- for each parametrization case-set it'll run your fixture
this means (in your example) that both invocations of your test will have my_function mocked to return 2 for the only call that happens
if you want to additionally parametrize the mocked function, I would suggest including it in your parametrize list:
#pytest.mark.parametrize(
('input', 'expect', 'mocked_ret'),
(
(1, 2, 2),
(3, 6, 6),
),
)
def test_my_function(input, expect, mocked_ret, mocker):
mocker.patch(f"{__name__}.my_function", return_value=mocked_ret)
assert my_function(input) == expect
disclaimer: I'm a pytest core dev

Create parameterized test fixtures that depend on other parameterized test fixtures?

I want to do something like this
def foo_bar(a, b):
""" The function I want to test """
return ...
def subparams(a):
return [some stuff based on what a is]
#pytest.fixture(scope='module', params=('foo', 'bar'))
def a(request):
# lengthy setup based on request.param
yield request.param
# teardown
#pytest.fixture(params=subparams(a))
def b(request):
return request.param
def test_foo_bar(a, b):
result = foo_bar(a, b)
assert <something about result>
In other words, I have a parameterized fixture a which simply takse
a normal list of parameters. For each value of a, I also have a function
subparams for generating associated parameters b. For the sake of argument, let's say that subparams is trivially implemented as follows
def subparams(a):
return [1, 2, 3] if a == 'foo' else [4, 5]
in which case I would want test_foo_bar to be invoked with the following:
'foo', 1
'foo', 2
'foo', 3
'bar', 4
'bar', 5
Unfortunately, the #pytest.fixture(params=subparams(a)) bit doesn't work because at that point a is still just a function, not an instantiation based on a's parameterization. How do I achieve the effect of having test_foo_bar called with those kinds of combinations of a and b where a takes a long time to set up (hence the scope='module' bit) and b is parameterized depending on a?

Scala function, unexpected behaviour

I have the following Scala code snippet:
(1 to 10).foreach(a => (1 to 100 by 3).toList.count(b => b % a == 0))
which, I would expect to behave like the following:
Create a list of multiple of 3 less than 100
For each item in the list previously generated, count how many multiples of 1, 2, 3... 10 there are
But, when I run the snippet, I get an empty list. What am I doing wrong?
Thanks for your help!
The behavior is totally expect when using foreach.
foreach takes a procedure — a function with a result type Unit — as the right operand. It simply applies the procedure to each List element. The result of the operation is again Unit; no list of results is assembled.
It's typically used for its side effects — something like printing or saving into a database, etc.
You ought using map instead :
scala> (1 to 10).map(a => (1 to 100 by 3).toList.count(b => b % a == 0))
// res3: scala.collection.immutable.IndexedSeq[Int] = Vector(34, 17, 0, 9, 7, 0, 5, 4, 0, 4)

Scala iterate over a set of objects

I have a sealed trait which is implemented by 3 objects
sealed trait MyTrait {
...
}
object A extends MyTrait { ... }
object B extends MyTrait { ... }
object C extends MyTrait { ... }
I'm using Scalaz's validation mechanism wherein the apply methods of the objects A, B and C return a validated type. the Objects A, B and C does contain some logic and I want to apply this logic sequentially, i.e., I want to first apply A and check what the result of A is and based on it, decide if I want to call B or just return the validated result. I want to repeat this until I hit C after which I just return whatever I get as a result of calling C.
Currently I have a static approach where I first call A, pass the result of A to a utility method and check for the result and then call B.
def apply(request: Request): Validated[Result] = {
val vResultA = run(request, A)
val vResultB = if (isResultOk(vResultA)) run(request, B) else vResultA
if (isResultOk(vResultB)) run(request, C) else vResultB
}
Is there a better way to do this? Any suggestions or any patterns that I can apply?
We will define succeeded results = results that are OK, and failed results = results that are not OK.
First, A, B, and C are all objects extending MyTrait. Therefore, they can be grouped into an Array or a List of MyTrait.
val objects = Array(A, B, C) /* You can use List instead if you want. */
Then the type of objects is Array[MyTrait].
Next, we have to iterate on this Array.
However, just calling map on this Array continues mapping even if the previous isResultOk() is false.
Therefore, we will use Stream instead of Array.
Let's see how using Stream can stop calling map if some condition is satisfied.
Array(1, 2, 3, 4, 5).map(i => {
println(i)
i + 100
}).takeWhile(_ <= 103).foreach(println(_))
The output of the above code will be:
1
2
3
4
5
101
102
103
So, map() ends, and then takeWhile() ends -- takeWhile() does not affect calling map().
However, if we do the same operations on the Stream,
Array(1, 2, 3, 4, 5).toStream.map(i => {
println(i)
i + 100
}).takeWhile(_ <= 103).foreach(println(_))
The output will be:
1
101
2
102
3
103
4
So the calling will be map() -> takeWhile() -> foreach() -> map() -> takeWhile() -> ...
At the end, 4 is printed, and 4 + 100 = 104 > 103 will be cut in takeWhile().
The following elements will be not accessed further.
So, do we have to use takeWhile?
objects.toStream.map(run(request, _)).takeWhile(isResultOk(_))
This will get rid of failed results, even though we need the first failed result if failure occured.
(i.e. This will make a problem if there is any result that is not OK.)
How about the opposite function dropWhile()?
objects.toStream.map(run(request, _)).dropWhile(isResultOk(_))
This will get rid of all succeeded results, even though all results are succeeded.
(i.e. This will make a problem if all results are OK.)
So, we will use span().
c.span(p) = (c.takeWhile(p), c.dropWhile(p))
We will test if there are results that are not OK.
If there is a result that is not OK, then we will return the first such result.
Otherwise, we will return the last result that is OK.
val (succ, fail) = objects.toStream.map(run(request, _)).span(isResultOk(_))
fail.headOption.getOrElse(succ.last)
fail.headOption will return Some(fail's first element) if fail is not empty, otherwise None.
In summary,
val objects = Array(A, B, C)
def apply(request: Request): Validated[Result] = {
val (succ, fail) = objects.toStream.map(run(request, _)).span(isResultOk(_))
fail.headOption.getOrElse(succ.last)
}