I've a function that I want to write unit tests for (function is a part of class A):
def funcA(self):
variable = self.attributes.method()
logger.info("Log")
this function is called from another function that initialize Class and save its object to self.attributes variable.
def funcB(self):
self.attributes = B()
# call funcA if certain criteria is met
and I have implementation of method function inside of B class definition.
How can I now write unit test for funcA?
I've tried to do it like this:
import classA as a
def test_funcA(self) -> None:
self.classA = a.A()
method_return = self.classA.funcA()
this gives me error 'A' object has no attribute 'attributes'
I also tried to mock this missing attribute by:
a.A.attributes = Mock(return_value={})
but then I got different error TypeError: Object of type Mock is not JSON serializable
I guess I need to somehow mock class B and the method function, so that my main method that I'm testing will just take the mocked return and assert if it logs correct message, right?
Your initial intuition about setting the attributes directly is probably the way to go. You should set the proper value - with the relevant properties B() would have returned.
Inside your test, you can do something in the form of self.classA.attributes = Bunch(mathod=lambda: "value for variable", another_attribute_used_inside_funcA = 20). See bunch library.
I created a Class with a staticmethod:
class DetfileDetector(Detector):
def __init__(self, file_path, **kwargs):
super().__init__(**kwargs)
self.detections = self.parse_detfile(file_path)
#staticmethod
def parse_detfile(file_path):
#do somthing with file_path
When I call parse_defile without instancing the class I get the expected result
DetfileDetector.parse_detfile('foo.txt')
However, when I call it from init() function I get the error:
TypeError: parse_detfile() takes 1 positional argument but 2 were
given
I assume that the meaning is that 'self' is also passed to the staticmethod, but this is a staticmethod therefore I expected that self will not be transferred.
My attempts to fix were to set 'file_path' as an optional argument with None as default but I got a TypeEroor of
TypeError: parse_detfile() got multiple values for argument 'file_path'
I Will appreciate if someone can tell me how to write it the right way.
Edit: thank you for your answers, adding more information:
I see now that it fails when I run it from 'python interactive shell' of VScode (version 1.50.0-insider), but passes from when running it from command line or without the interactive shell. I shall report this issue to VScode developers.
I'm using python 3.7.7
Edit2: the content of Detector class
class Detector:
def __init__(self, **kwargs):
self.every = kwargs.pop('every', 1)
self.min_confidence = kwargs.pop('min_confidence', .8)
self.min_wh = kwargs.pop('min_wh', 5)
self.min_ar = kwargs.pop('min_ar', .1)
self.sensor_noise_cov = np.square(np.diag(kwargs.pop('sensor_noise', [10, 10, 1, 10])))
self.classes = object_classes(kwargs.pop('cars_only', True))
Your code is actually correct.
I tested it with Python 3.8 and didn't see any problem.
You can call a staticmethod using the class, or an instance of that class.
See here: https://docs.python.org/3/library/functions.html#staticmethod
It was working like this even in older versions of Python, I checked all the way to Python 2.7.
So there's a bit of a mystery of why you're getting that error.
Maybe give more context on your code?
I think the issue is not from the code you showed. Tested on Python 3.6, this works:
class Detector:
pass
class DetfileDetector(Detector):
def __init__(self, file_path, **kwargs):
super().__init__(**kwargs)
self.detections = self.parse_detfile(file_path)
#staticmethod
def parse_detfile(file_path):
#do somthing with file_path
print(file_path)
DetfileDetector('get.txt')
# get.txt
DetfileDetector.parse_detfile('tex.txt')
# tex.txt
In VSCode, add breakpoints on your code at init and parse_detfile and run your code on debug mode to see the variables.
So check Detector and see if the issue is there.
Change your code to this and it should work
class DetfileDetector(Detector):
def __init__(self, file_path, **kwargs):
super().__init__(**kwargs)
self.detections = DetfileDetector.parse_detfile(file_path)
#staticmethod
def parse_detfile(file_path):
#do somthing with file_path
I assume that the meaning is that 'self' is also passed to the staticmethod, but this is a staticmethod therefore I expected that self will not be transferred.
Correct.
Half the point of a staticmethod is that you don't need an instance. However, it is still an attribute of the class, not a top-level function, so:
I Will appreciate if someone can tell me how to write it the right way.
you need to look for it within the class, thus:
def __init__(self, file_path, **kwargs):
super().__init__(**kwargs)
self.detections = DetfileDetector.parse_detfile(file_path)
Yes, it's a bit awkward, arguably. But the other half of the point of staticmethod is that you actually associate the method with the class this way. If that doesn't seem like a benefit, you might instead consider just making a plain, top-level function, outside the class.
I had the same issue. In my case, this was caused because I had created two modules that had a class with the same name, and the information of the error made me think that the error was in one of the files, when in reality, it was in the other file. See minimal working example below.
As you can see below, the issue is caused because I call file1.Foo and provide a parameter, even though its constructor doesn't accept a single parameter. I was confused because the error mentions Foo.__init__(), so I thought this referred to the Foo class in file1.py or the one in file2.py.
file1.py
class Foo():
def __init__(self):
print('Hello from file1.py')
file2.py
import file1
class Foo():
def __init__(self, text):
pass
def f1(text):
return 'Hello from f1 - ' + text
def f2(self):
bar = file1.Foo(Foo.f1('a'))
a = Foo()
a.f2()
Results of execution
python file2.py
Traceback (most recent call last):
File "/home/myusername/e/file2.py", line 15, in <module>
a.f2()
File "/home/myusername/e/file2.py", line 12, in f2
bar = file1.Foo(Foo.f1('a'))
TypeError: Foo.__init__() takes 1 positional argument but 2 were given
As you might expect, the issue was simply solved by adding a parameter to the constructor in file1.py.
file1.py
class Foo():
def __init__(self, text):
print(f'Hello from file1.py')
file2.py
import file1
class Foo():
def __init__(self):
pass
def f1(text):
return 'Hello from f1 - ' + text
def f2(self):
bar = file1.Foo(Foo.f1('a'))
a = Foo()
a.f2()
Results of execution
python file2.py
Hello from file1.py
If you are having the same issue, I'd recommend you take a look at those classes that have the same name as the one mentioned in the error.
Hi I have the following test classes
logintests.py:
class SignOnTests(BaseTest):
def test_login_info(self):
#some code
passwordtests.py:
class ResetPasswordTests(unittest.TestCase):
def test_mytest(self):
#somecode
#Should Call SignOnTests.test_login_info()
I've tried putting on passwordtests.py:
from logintests import SignOnTests
But keep gettingTypeError: unbound method test_login_info() must be called with SignOnTests instance as first argument (got nothing instead)
Is it possible to call a test method within another module?
I have a program1.py that has the following structure:
program1.py
class program1_class()
def __init(self,var1):
command1
def method2(self,var1):
Then I have a program2 that imports the the class and needs to access the method2
program2.py
from program1_class import program1_class()
def method2(var1):
call_method2 = program1_class.method2(var1)
When I do this, I get the error
TypeError: unbound method predict_prob() must be called with LogisticRegressionSGD instance as first argument (got list instance instead)
There are a couple problems here-
from program1_class import program1_class() is invalid syntax in several ways.
The correct import statement is
from program1 import program1_class
Second, you tried to call a bound instance method on a class.
call_method2 = program1_class.method2(var1)
If you look at program1 you'll see that method2 is defined on the instance. You can tell this because the first argument is self. You call this by intantiating an instance of the class and then calling the method.
call_method2 = program1_class().method2(var1)
I'm trying to pass a dictionary that was initialized in one class as an argument into a method in another class. I wrote this code but no matter how I try to fix it I can't get going to test my other code..
I was trying to pass myDict as an argument in functionname by having class B inherit class A (I'm going to have other classes that will inherit class A and will have a function that takes myDict as an argument as well).
I have this:
class A(object):
def __init__(self):
class B(A):
.....
def functionname(self, myDict):
.....
def otherfunction(text):
text = function(otherargument) #this function returns a list and for each item in the list I call functionname.
myDict = {}
for x in text:
x.functionname(myDict)
I thought this would work but when I try to test my other code I get: TypeError: functionname() takes exactly 2 arguments (1 given). Am I not approaching this the right way?
This is homework so I would really appreciate some guidance on understanding the concept of this.
Edit: I called functionname from another function outside of the classes.
The error also starts at the function call (x.functionname()) and says TypeError
Edit: So I tried moving the dictionary that I declared in init to otherfunction and it worked and gave me different errors for other parts of code that needs to be fixed. But for this error, it was solved.