How to pytest monkeypatch multiple argv arguments? - pytest

I'm only able to test one argument e.g. animal. Every other added argument fails e.g. name. What must I change?
pytest foo.py returns pytest: error: the following arguments are required: name
### foo.py ###
import argparse
import pytest
import sys
#pytest.mark.parametrize('animal_input', ['cat'])
#pytest.mark.parametrize('name_input', ['tom'])
def test_get_bake_progress(monkeypatch, animal_input, name_input):
with monkeypatch.context() as m:
m.setattr(sys, 'argv', ['--animal', animal_input])
m.setattr(sys, 'argv', ['--name', name_input])
assert foo() == (animal_input)
def foo():
parser = argparse.ArgumentParser()
parser.add_argument('animal')
parser.add_argument('name')
args = parser.parse_args()
animal = args.animal
name = args.name
return animal

Related

In Scala cats 2.x, how to create a generic zero functor (given its type class)?

I'm looking for a method to initialise a zero functor z: F[_], given the type class Functor[F[_]]. The zero functor should ensure that any other function compose with it yields a fixed point. I've tried the following code:
import cats.Functor
import cats.syntax.functor._
import cats.instances.option._
import cats.instances.list._
def zeroFunctor[F[_]: Functor]: F[Nothing] = {
val functorInstance = implicitly[Functor[F]]
functorInstance.map(functorInstance.empty)(_ => ??? : Nothing)
}
val optZero = zeroFunctor[Option] // None
val listZero = zeroFunctor[List] // Nil
But it failed with the following information:
[Error] /home/peng/git/spookystuff/parent/core/src/main/scala/com/tribbloids/spookystuff/utils/SpookyViews_Imp0.scala:45:41: value empty is not a member of cats.Functor[F]
SO what is the proper way to create it?

Patching class does not work its definition is get from dict

I have a problem with patching, how can I patch A class properly?
a.py
class A:
pass
plugin.py
from a import A
CONFIG = {'aenum': A}
def do():
instance = CONFIG['aenum']() # the A class is NOT patched using this
# instance = A() # the test passes with this
return instance.auth()
test.py (using pytest to run)
from unittest.mock import Mock, patch
import plugin
def test_do():
a_instance_mock = Mock()
a_instance_mock.auth.return_value = 42
with patch("plugin.A", return_value=a_instance_mock):
assert plugin.do() == 42
patch overrides only the specific item from given namespace; the class name is patched AFTER a module is imported, not in the importation time.
That is why the CONFIG["aenum"] is left untouched.
Use patch.dict instead
from unittest.mock import Mock, patch
from plugin import do
def test_do():
a_instance_mock = Mock()
a_instance_mock.authenticate.return_value = 42
a_class_mock = Mock(return_value=a_instance_mock)
with patch.dict("plugin.CONFIG", {"aenum": a_class_mock}):
assert do() == 42

Using pytest patch decorator to test ray actors remote function

I'm trying to run unit test for a ray remote function. I am using a #patch decorator to patch the remote function. The
foo.py
class Foo(object):
def __init__(self):
self.value = 0
def bar(self):
self.value = 100
print("In original method")
assert False
test_foo.py
from unittest.mock import patch
import pytest
import unittest
import ray
from tests.foo import Foo
#pytest.fixture
def ray_fixture():
print("Initializing ray")
if not ray.is_initialized():
ray.init()
yield None
print("Terminating ray")
ray.shutdown()
def fake_bar(self):
print("In fake method")
assert True
#pytest.mark.usefixtures("ray_fixture")
class FooTestCase(unittest.TestCase):
"""Test cases for Foo module"""
#patch("foo.Foo.bar", new=fake_bar)
def test_bar(self):
Foo().bar()
#patch("foo.Foo.bar", new=fake_bar)
def test_bar_remote(self):
foo_actor = ray.remote(Foo).remote()
obj_ref = foo_actor.bar.remote()
ray.get(obj_ref)
The test test_bar passes and test_bar_remote fails.
If I use ray.init(local_mode=True) then both tests pass. I can not use local_mode=True due to other limitations.
How can we patch ray actor's remote method using #patch?
Here's an alternative. Subclass Foo with a stubbed/mocked implementation and use it in ray. That way, the Foo class would be intact, you would only update those that needs to be mocked e.g. the method bar().
test_foo.py
...
class FooStub(Foo):
def bar(self, *args, **kwargs):
print("In another fake method")
assert True
# Optionally, you can also call the real method if you want. You may update the arguments as needed.
# super().bar(*args, **kwargs)
#pytest.mark.usefixtures("ray_fixture")
class FooTestCase(unittest.TestCase):
...
def test_bar_remote(self):
foo_actor = ray.remote(FooStub).remote()
obj_ref = foo_actor.bar.remote()
ray.get(obj_ref)
...
Output
$ pytest -q -rP
..
================================================================================================= PASSES ==================================================================================================
__________________________________________________________________________________________ FooTestCase.test_bar ___________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout setup ------------------------------------------------------------------------------------------
Initializing ray
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
In fake method
---------------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------------
Terminating ray
_______________________________________________________________________________________ FooTestCase.test_bar_remote _______________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout setup ------------------------------------------------------------------------------------------
Initializing ray
---------------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------------
Terminating ray
2 passed, 1 warning in 5.03s
I have found a below hacky way which involves change in original function (and check env variable to provide test implementation)
import os
class Foo(object):
def __init__(self):
self.value = 0
def bar(self):
self.value = 100
if os.environ.get['TEST'] == 'True':
print("In fake method")
assert True
else:
print("In original method")
assert False
runtime_env = {"env_vars": {"TEST": "True"}}
ray.remote(Foo) .options(runtime_env=runtime_env) .remote()

Def macro - scala 2.13 - not found: value cond

I am trying to make working an example from the scala docs:
https://docs.scala-lang.org/overviews/macros/overview.html
I have two files:
object Main extends App {
println("Testing assert macro...")
val result = Asserts.assert(true, "abc")
}
and:
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
object Asserts {
val assertionsEnabled: Boolean = true
def assert(cond: Boolean, msg: Any): Unit = macro Asserts.assertImpl
private def raise(msg: Any) = throw new AssertionError(msg)
def assertImpl(c: Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]) : c.Expr[Unit] = {
import c.universe._
if (assertionsEnabled)
c.Expr(q"if (!cond) raise(msg)")
else
c.Expr(q"()")
}
}
but I am getting an error:
Error:(8, 30) not found: value cond val result =
Asserts.assert(true, "abc")
any idea how to make it working ?
thanks!
Macros and main code must be in different subprojects
https://www.scala-sbt.org/1.x/docs/Macro-Projects.html
You missed dollar signs ($cond, $msg instead of cond, msg), otherwise while the macro is expanded inside Main you're trying to use absent local variables cond, msg rather than splice parameters cond, msg of the macro. Also it must be known inside Main that raise is Asserts.raise so either use import Asserts.raise in Main or fully qualified name in the quasiquote. Try
c.Expr(q"if (!$cond) Asserts.raise($msg)")
Also Asserts.raise must be accessible inside Main so remove private.

Can not use autouse fixture to import module

I have a test module has one autouse fixture
import pytest
#pytest.fixture(autouse=True):
def set_env_config(monkeypatch):
palladium_config = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'config.py')
monkeypatch.setenv('PALLADIUM_CONFIG', palladium_config)
from A import B
and in every followed test within this test module class B is needed, but this importation can not be achieved for any tests.
In the other way, I patch only the environment variable only
#pytest.fixture(autouse=True):
def set_env_config(monkeypatch):
palladium_config = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'config.py')
monkeypatch.setenv('PALLADIUM_CONFIG', palladium_config)
and import the class B in every test case, it succeeded.
Why is that ? why can't I import class within autouse fixture
thanks a lot
I am guessing that you are expecting something like the following:
#pytest.fixture(autouse=True)
def do_an_import():
from A import B
def test_foo():
assert B.do_my_thing() == 'foo'
That doesn't work, while doing the following does what you want:
def test_foo():
from A import B
assert B.do_my_thing() == 'foo'
Unfortunately doing an import in the fixture (the first example) will add B into that fixture function's namespace, but not the test function's namespace.
Similarly, this wouldn't work for the same reason:
#pytest.fixture
def not_an_autouse_fixture():
from A import B
def test_foo(not_an_autouse_fixture):
assert B.do_my_thing() == 'foo'
B is being imported into the fixture's namespace, which is different from the test's namespace. You could instead do:
#pytest.fixture
def Cls():
from A import B
return B
def test_foo(Cls):
assert Cls.do_my_thing() == 'foo'
or you could import it at the top level of your module like:
from A import B
def test_foo(B):
assert B.do_my_thing() == 'foo'