Weird behavior of nosetest - python

I try to use nose test
But when i run the testcase below
import unittest
class TestSuite(unittest.TestCase):
b = []
def setUp(self):
self.b.extend([10, 20])
def tearDown(self):
self.b = []
def test_case_1(self):
self.b.append(30)
assert len(self.b) == 3
assert self.b == [10, 20, 30]
def test_case_2(self):
self.b.append(40)
assert len(self.b) == 3
assert self.b == [10, 20, 40]
But all test cases is not pass
$> nosetest test_module.py
.F
======================================================================
FAIL: test_case_2 (test_module2.TestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/knt/test_module2.py", line 19, in test_case_2
assert len(self.b) == 3
AssertionError
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
What 's happend ??? I expect after run test_case_1, tearDown will be called, so self.b is []. So with next test case test_case_2, setUp run and self.b is [10, 20].
But in fact, at setUp value of self.b is [10, 20, 30].
I dont know why. I think there must be some problems with statement self.b = [].
Anything related pointers, I guess?
I still didn't figure it out, but i find way to fix this bug. Just change self.b = [] to del self.b[:].
Anyone can help me find out the problem?
Thank you so much.

As far as I can tell the problem maybe with the way unitests works and how class fields work in python here is a simple test:
class A:
b = []
def reset(self):
self.b = []
a = A()
a.b.append(3) # we are actually accessing the class variable here
print A.b is a.b # True
print a.b # [3] same here
a.reset() # We just hid the class variable with our own which points to []
print A.b is a.b # False as expected.
print a.b # [] we think its being clear but rather we are using our own not the class variable
b = A()
print b.b # [3] b here is using the class that a previously modified but is no longer pointing to
print b.b is A.b # True
# Also note
c = A()
d = A()
print c.b is d.b # True, since both are using the same class variable.
I think unittest is creating the object multiple times, for each test function, creates object, fires setup which access the class variable, the test runs, calls teardown which simply hides it, creates another object, calls setup which access the same class variable that the previous object modified and didn't affect since its tear down simply created a new instance binded to self, hiding the class version.
we always declare member fields inside the __init__ using self.
def __init__(self):
self.b = []
this way every instance will have its own copy, though we can't do this here since we are inheriting from unittest.TestCase thats why we have setUp
import unittest
class TestSuite(unittest.TestCase):
def setUp(self):
self.b = [10, 20]
def tearDown(self):
self.b = []
def test_case_1(self):
self.b.append(30)
assert len(self.b) == 3
assert self.b == [10, 20, 30]
def test_case_2(self):
self.b.append(40)
assert len(self.b) == 3
assert self.b == [10, 20, 40]

The problem is your class attribute in line 2:
b = []
That is an attribute on the class TestSuite. Nosetests creates a new instance of the class TestSuite, and then calls setUp. In setUp, you modify the class attribute on the class TestSuite:
self.b.extend([10, 20])
Then, in tearDown, after your first test has been run, you create a new list and assign it to a new instance attribute which is also happens to be called b:
self.b = []
This does not modify the class attribute at all. Further attempts to access self.b from this instance will return the instance attribute, not the class attribute.
But this has no effect, because the very next thing that happens is that nosetests throws away the current instance of TestSuite, including your new, empty list in the instance attribute b that you have set in tearDown.
Then nosetests creates a brand new instance of the class TestSuite, to run your second test. But the class TestSuite still has a b class attribute containing [10, 20, 30], because it was modified while your first test was running.
Then nosetests setUp method runs, adds 10 and 20 to TestSuite's class attribute b. Then your second test runs, adds 40 to TestSuite's class attribute, and your second test fails, because it finds six items in that class attribute:
[10,20,30,10,20,40]
The reason that del self.b[:] works is because, just like append, del is modifying the class attribute, rather than creating a new instance attribute.
Make sure you understand the difference between classes and instances, and between class attributes and instance attributes, otherwise you will be plagued with similar problems for as long as you are working with Python.

Well, try to replace the:
self.b.extend([10,20])
with
self.b = [10,20]
and maybe throw out the class variable, you don't need it and it might be the reason this happens.

Related

Use mock or create real instance with workaround while testing

I have class MyClass in file main.py
class MyClass:
def __init__(self, a=1, b=2, c=3):
self.a = a
self.b = b
self.c = c
self.d = None
self.e = None
self.f = None
def method_1(self):
return self.a + self.b
def method_2(self):
return self.d + 4
def method_3(self):
return self.e + 10
def run(self):
self.d = self.method_1()
self.e = self.method_2()
self.f = self.method_3()
# a lot more stuff here that takes time
and I have the following tests in file test_file.py
import unittest
from unittest.mock import patch
from main import MyClass
class TestMyClass(unittest.TestCase):
def test_method_2_v1(self):
# This test creates a real instance, but the input self.d is created manually in the test,
# in a different way it is done in the production code (in the production code it is done through run())
instance = MyClass()
instance.d = instance.method_1()
instance.e = instance.method_2()
assert instance.e == 7
def test_method_2_v2(self):
# This test creates a real instance, but the input self.d is created manually in the test,
# in a different way it is done in the production code (in the production code it is done through run())
# This case does not run method_1, but gives an explicit value to self.d
instance = MyClass()
instance.d = 3
instance.e = instance.method_2()
assert instance.e == 7
#patch('main.MyClass', spec=True)
def test_method_2_v3(self, my_class_mock):
# This test uses a mock
mock_instance = my_class_mock()
mock_instance.configure_mock(d=3)
assert MyClass.method_2(mock_instance) == 7
I believe the comments and the code clearly explain the differences.
Which one is the best practice and why?
Is there a better solution?
Main difference between the 3 methods
I think that the main difference between the 3 test methods is:
test_method_2_v1() invokes method_1() of MyClass
test_method_2_v2() and test_method_2_v3() don't invoke method_1() of MyClass
This means that test_method_2_v1() executes an indirect test of method_1() while the other 2 test methods execute only a test of method_2().
Comparison between test_method_2_v2() and test_method_2_v3()
Between test_method_2_v2() and test_method_2_v3() I think that the best is test_method_2_v3() because the use of a mock object, when it is possible, is in general preferable because it helps to create unit tests (a mock object is used to simulate the behaviour of an object in a precise test case and not an whole object).
A unit test is a test which verifies a specific functionality. In this case test_method_2_v3() verifies that method_2() returns the value of the attribute d increase of 4.
In my opinion test_method_2_v2() does too many things so it's not a good unit test.
How test_method_2_v2() becomes a unit-test
I think is better to modify test_method_2_v2() and a possible code for it is the following:
def test_method_2_v2(self):
instance = MyClass()
instance.d = 3
# check that method_2 return 'd' increases of 4
assert instance.method_2() == 7
Previous code becomes similar to test_method_2_v3() without using of mock object. Now test_method_2_v2() only verifies the correctness of method_2() (as a test unit must do).

Mock instance attributes without instance

I would like to test by mocking an instance's attribute, but I do not have access to the instance beforehand. How can I mock the attribute without it? Here is my minimum reproducible code.
# test.py
class Foo:
def __init__(self, x):
self.x = x
def bar():
return Foo(1).x + 1
def test_bar(mocker):
mocker.patch('test.Foo.x', 2)
assert bar() == 3
$ pytest test.py
FAILED test.py::test_bar - AttributeError: <class 'test.Foo'> does not have the attribute 'x'
This makes sense since the Foo class doesn't have an x, only instances. If I add a kwarg mocker.patch('test.Foo.x', 2, create=True) I then get this
$ pytest test.py
FAILED test.py::test_bar - assert 2 == 3
since Foo.x will get mocked but overridden when the instance later sets self.x = x.
The standard way to do this kind of test is to mock the entire class, like so:
def test_bar(mocker):
mock_foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_foo)
mock_foo.return_value.x = 2
assert bar() == 3
mock_foo.assert_called_once_with(1)
So in this case, you mock the entire Foo class.
Then, there is this syntax mock_foo.return_value.x = 2: where mock_foo.return_value simply means the return object when calling Foo(1) - which is your object. Since we mocked the entire class - the __init__ method does nothing - so you need to set the x attribute on your own.
Also note the mock_foo.assert_called_once_with(1) - which checks that Foo(1) was called with the right parameter.
p.s.
To simplify this kind of mocking, I created a pytest fixture called pytest-mock-generator. You can use it to help you create the mocks and asserts.
You start with using the mg fixture to analyze your bar method so it locates the relevant mocks for you:
def test_bar(mocker, mg):
mg.generate_uut_mocks(bar)
When this test method is executed, it generates the following code (prints it to the console and copies it to your clipboard for quick usage):
# mocked dependencies
mock_Foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_Foo)
You then modify the test function and execute the bar method and use the generate_asserts capability:
def test_bar(mocker, mg):
# mocked dependencies
mock_Foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_Foo)
bar()
mg.generate_asserts(mock_Foo)
This gives you the following output:
assert 1 == mock_Foo.call_count
mock_Foo.assert_called_once_with(1)
mock_Foo.return_value.x.__add__.assert_called_once_with(1)
You don't need most of it, but you can keep the second line for your assert and the modify the third line so x has the right value:
def test_bar(mocker):
mock_foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_foo)
mock_foo.return_value.x = 2
assert bar() == 3
mock_foo.assert_called_once_with(1)

Returning class to itself in python

Very simple question here, but I am new to python as an object oriented programming language. I am trying to write a class. Imagine it is organized as follows:
class myClass:
def __init__(self,a,b,runit=True):
self.a = a
self.b = b
if runit:
self.run_func()
def run_func(self):
self.c = self.a*self.b
return
So as you can see the class is initialized with just a and b. It defaults to initialize c from those arguments, but it need not. Now let me illustrate three use cases that I think should behave the same, but are not:
# Use 1
test = myClass(5,2)
print(test.c)
# Use 2
test = myClass(5,2,runit=False)
test.run_func()
print(test.c)
# Use 3
test = myClass(5,2,runit=False).run_func()
print(test.c)
This returns the following:
10
10
Traceback (most recent call last):
File "<ipython-input-37-cb854baa3a0c>", line 23, in <module>
print(test.c)
AttributeError: 'NoneType' object has no attribute 'c'
Why can the instantiated class not be operated on immediately and pipe this result to test in one step? In my head, (1) and (2) are the same set of operations except one is broken into two steps and the other is done in one line.
And, more importantly, how can I fix this by editing my class to behave in the expected manner?
at # Use 3 myClass(5,2,runit=False).run_func() returns None
to fix you could return self:
def run_func(self):
self.c = self.a*self.b
return self
test = myClass(5,2,runit=False).run_func()
print(test.c)
output:
10
or you should not set your flag runit to False and use:
class myClass:
def __init__(self,a,b,runit=True):
self.a = a
self.b = b
if runit:
self.run_func()
def run_func(self):
self.c = self.a*self.b
test = myClass(5,2)
print(test.c)
output:
10
run_func should return self:
def run_func(self):
self.c = self.a*self.b
return self
stating return without a value following it, is the same as writing return None.
You get this exception because None has no attribute named c.
In the 3rd case, test is assigned the return value of run_func(). It has a bare return which returns None, so test = None.
In case 3
test = myClass(5,2,runit=False).run_func()
print(test.c)
test is not the object, but the return of the run_func(), which is null and indeed has no c attribute
Lets look at the method call in question:
test = myClass(5,2,runit=False).run_func()
Let's break that down. First, you construct an instance of myClass and then you call run_func on that instance. It's the return value of run_func that you assign to test and since run_func doesn't return anything test is None resulting in your error.
As another way to see this, try the following:
class myClass:
def __init__(self,a,b,runit=True):
self.a = a
self.b = b
if runit:
self.run_func()
def run_func(self):
self.c = self.a*self.b
return 11
test = myClass(5,2,runit=False).run_func()
print(test) # will print 11

How can I reuse another classes' method without inheritance in Python 2?

Two of my classes need to have the same method, but they are not related by inheritance.
The following works in Python 3:
class A(object):
def __init__(self):
self.x = 'A'
def printmyx(self):
print(self.x)
class B(object):
def __init__(self):
self.x = 'B'
printmyx = A.printmyx
a = A()
b = B()
a.printmyx()
b.printmyx()
and prints
A
B
However, in Python 2 I'm getting
Traceback (most recent call last):
File "py2test.py", line 18, in <module>
b.printmyx()
TypeError: unbound method printmyx() must be called with A instance as first argument (got nothing instead)
I think the problem is that in Python 3 printmyx is just a regular function while in Python 2 it's an unbound method.
How to make the code work in Python 2?
edit
In my real code, A and B inherit from different parent classes. They need to share one helper method but have no other relation to each other.
Bear in mind that Python does support multiple inheritance, so it's very possible to define a mixin class and have both A and B inherit from it without disturbing the main inheritance hierarchy. I understand you're saying the classes have little in common - but they do both have a variable called x and a method to print it - and to me at least, that's enough in common to consider using inheritance.
But that said, another way to do this is using a class decorator to add the common method:
def add_printmyx(original_class):
def printmyx(self):
print (self.x)
original_class.printmyx = printmyx
return original_class
#add_printmyx
class B(object):
def __init__(self):
self.x = 'B'
b = B()
b.printmyx()
The class decorator takes the original class and adds (or replaces) a printmyx method that prints the contents of x.
Apparently, in Python 2 the original function an unbound method was created from is stored in the im_func attribute.1
To make the code work in Python 2 like it does in Python 3, use
printmyx = A.printmyx.im_func
in B's body.
1 Described in the The standard type hierarchy
section of the Python 2 Data Model documentation.
Why is inheritance not allowed? This is the perfect use case for inheritance.
class Common(object):
def printmyx(self):
print(self.x)
class A(Common):
def __init__(self):
self.x = 'A'
class B(Common):
def __init__(self):
self.x = 'B'
a = A()
b = B()
a.printmyx()
b.printmyx()

nested classes in Python

Dealing with classes (nested etc) does not look easy in Python, surprisingly! The following problem appeared to me recently and took several hours (try, search ...) without success. I read most of SO related links but none of them has pointed the issue presented here!
#------------------------------------
class A:
def __init__(self):
self.a = 'a'
print self.a
class B(A):
def __init__(self):
self.b = 'b'
A.a = 'a_b'
print self.b, A.a
#------------------------------------
class C:
class A:
def __init__(self):
self.a = 'a'
print self.a
class B(A):
def __init__(self):
self.b = 'b'
A.a = 'a_b'
print self.b, A.a
#------------------------------------
#------------------------------------
>>> c1 = A()
a
>>> c1.a
'a'
>>> c2 = B()
b
>>> c2.a, c2.b
('a_b', 'b')
>>> c3 = C()
>>> c4 = c3.A()
a
>>> c4.a
'a'
>>> c5 = c3.B()
b a_b
>>> c5.b
'b'
>>> c5.a
Traceback (most recent call last):
File "", line 1, in
AttributeError: B instance has no attribute 'a'
Where is the problem in the code?
AND
In both cases it seems that when B(A) is initialized A() is not initialized. What is the solution for this issue? Note that the term A.__init__() being called inside B()'s __init__() does not work!
Updates:
class Geometry:
class Curve:
def __init__(self,c=1):
self.c = c #curvature parameter
print 'Curvature %g'%self.c
pass #some codes
class Line(Curve):
def __init__(self):
Geometry.Curve.__init__(self,0) #the key point
pass #some codes
g = Geometry()
C = g.Curve(0.5)
L = g.Line()
which results in:
Curvature 0.5
Curvature 0
what I was looking for.
The code executed in a method runs in the local scope of that method. If you access an object that is not in this scope, Python will look it up in the global/module scope, NOT in the class scope or the scope of any enclosing class!
This means that:
A.a = 'a_b'
inside C.B.__init__ will set the class attribute of the global A class, not C.A as you probably intended. For that you would have to do this:
C.A.a = 'a_b'
Also, Python will not call parent methods if you override them in subclasses. You have to do it yourself.
The scoping rules mean that if you wanted to call the __init__ method of the parent class inside C.B.__init__, it has to look like this:
C.A.__init__(self)
and NOT like this:
A.__init__(self)
which is probably what you've tried.
Nested classes seems so unpythonic, even if considered as factories. But to answer your question: There simply is no c5.a (instance of C.B). In the init-method of C.B you add to the CLASS C.A an attribute a, but not to C.B! The class A does already have an attribute a, if instantiated! But the object of class B (and even the class) doesn't!
You must also keep in mind, that __init__ is not an constructor like in C++ or Java! The "real constructor" in python would be __new__. __init__ just initializes the instance of a class!
class A:
c = 'class-attribute'
def __init__(self):
self.i = 'instance-attribute'
So in this example c is a class-attribute, where i is an attribute of the instance.
Even more curios, is your attempt to add an attribute to the baseclass at the moment of the instantiation of the child-class. You are not getting a "late" inheritance-attribute that way.
You simply add to the class A an additional attribute, which surprises me to even work. I guess you are using python 3.x?
The reason for this behaviour? Well, i guess it has to do with pythons neat feature that in python definitions are executed(AFAIK).
The same reason why:
def method(lst = []):
is almost ever a bad idea. the deafult-parameter gets bound at the moment of the definition and you won't generate a new list-object every-time you call the method, but reusing the same list-object.

Categories