Python unittest : setUpClass uses a non-static method - python

I'm quite a beginner in Python and started designing a unit test in Python and i need to post some messages to the server before i run the test class (cause it's gonna search for them). Thus i need to call a non-static method postMessages().
the stack-trace of the error i'm getting is this-
Error
Traceback (most recent call last):
File ".../TestMsgs.py", line 23, in setUpClass
instance = cls()
File ".../python2.7/unittest/case.py", line 191, in __init__
(self.__class__, methodName))
ValueError: no such test method in <class 'TestMsgs.TestMsgs'>: runTest
i have something like this in the code:
class A(object):
def postMessages(self):
print "i post messages in the server!"
class B(A):
#classmethod
def setUpClass(cls):
cls.foo() # should post messages for the tests in the class to work on
There's no option, right now, to make foo static. How can i instantiate B (or A, for that matter) in postMessages() so i can use it in setUpClass() ?

After having a read through the __init__ method for TestCase I see that you need to provide a test method name to it. The default is "runTest" which is why that error was popping up.
import unittest
class A(unittest.TestCase):
def postMessages(self):
print "i post messages in the server!"
class B(A):
#classmethod
def setUpClass(cls):
cls.foo(cls(methodName='test_method')) # should post messages for the tests in the class to work on
def foo(self):
self.postMessages()
def test_method(self):
pass
B.setUpClass()
You can see it running in an interactive Python console here. It will print out "i post messages in the server!"
The reason you need to pass in a valid method name in the class can be clearly seen in the source code for unittest:
class TestCase:
"""A class whose instances are single test cases."""
def __init__(self, methodName='runTest'):
"""Create an instance of the class that will use the named test
method when executed. Raises a ValueError if the instance does
not have a method with the specified name.
"""
try:
self._testMethodName = methodName
testMethod = getattr(self, methodName)
self._testMethodDoc = testMethod.__doc__
except AttributeError:
raise ValueError, "no such test method in %s: %s" % \
(self.__class__, methodName)
If you want to pass in parameters to the method that you have just passed in then you would need to do something like
class A(unittest.TestCase):
def foo(self, arg1):
pass
a = A(methodName='foo')
a.foo('an_argument')
But this whole question just feels really wrong. You should refactor rather than have a static method calling an instance method. It's just silly.

Related

python child class method calling overridden classmethod with non-classmethod

I am trying to do the following in python3:
class Parent:
#classmethod
def show(cls, message):
print(f'{message}')
#classmethod
def ask(cls, message):
cls.show(f'{message}???')
class Child(Parent):
#property
def name(self):
return 'John'
def show(self, message):
print(f'{self.name}: {message}')
instance = Child()
instance.ask('what')
But it then complains
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in ask
TypeError: Child.show() missing 1 required positional argument: 'message'
even so child.show works as expected. So it seems that child.ask is calling Parent.show... I tried to mark Child.show as classmethod too, but then the cls.name is not showing the expected output:
class Child2(Parent):
#property
def name(self):
return 'John'
#classmethod
def show(cls, message):
print(f'{cls.name}: {message}')
instance2 = Child2()
instance2.ask('what')
this shows
<property object at 0xfc7b90>: what???
Is there a way to override a parent classmethod with a non-classmethod, but keeping other parent classmethod to call the overridden one?
I found it hard to follow for the second half of the question but there was an issue I saw and it might help you solve your problem.
When you said even so child.show works as expected. So it seems that child.ask is calling Parent.show, thats not what is happening.
When you called instance.ask("what"), it called the #classmethod decorated method of the Child class (which is inherited from the parent). This ask method is passing the class Child as the first argument, (not the instance you created). This means the line
cls.show(f'{message}???')
is equivalent to
Child.show(f'{message}???') # because cls is the Class not the instance
The show method inside the Child class is an instance method and expects the first argument to be the actual instance (self) but the string f'{message}???' is being passed to it and it expects a second message string to be passed so that's why its is throwing an error.
Hope this helped

How to make an Python subclass uncallable

How do you "disable" the __call__ method on a subclass so the following would be true:
class Parent(object):
def __call__(self):
return
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
object.__setattr__(self, '__call__', None)
>>> c = Child()
>>> callable(c)
False
This and other ways of trying to set __call__ to some non-callable value still result in the child appearing as callable.
You can't. As jonrsharpe points out, there's no way to make Child appear to not have the attribute, and that's what callable(Child()) relies on to produce its answer. Even making it a descriptor that raises AttributeError won't work, per this bug report: https://bugs.python.org/issue23990 . A python 2 example:
>>> class Parent(object):
... def __call__(self): pass
...
>>> class Child(Parent):
... __call__ = property()
...
>>> c = Child()
>>> c()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: unreadable attribute
>>> c.__call__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: unreadable attribute
>>> callable(c)
True
This is because callable(...) doesn't act out the descriptor protocol. Actually calling the object, or accessing a __call__ attribute, involves retrieving the method even if it's behind a property, through the normal descriptor protocol. But callable(...) doesn't bother going that far, if it finds anything at all it is satisfied, and every subclass of Parent will have something for __call__ -- either an attribute in a subclass, or the definition from Parent.
So while you can make actually calling the instance fail with any exception you want, you can't ever make callable(some_instance_of_parent) return False.
It's a bad idea to change the public interface of the class so radically from the parent to the base.
As pointed out elsewhere, you cant uninherit __call__. If you really need to mix in callable and non callable classes you should use another test (adding a class attribute) or simply making it safe to call the variants with no functionality.
To do the latter, You could override the __call__ to raise NotImplemented (or better, a custom exception of your own) if for some reason you wanted to mix a non-callable class in with the callable variants:
class Parent(object):
def __call__(self):
print "called"
class Child (Parent):
def __call__(self):
raise NotACallableInstanceException()
for child_or_parent in list_of_children_and_parents():
try:
child_or_parent()
except NotACallableInstanceException:
pass
Or, just override call with pass:
class Parent(object):
def __call__(self):
print "called"
class Child (Parent):
def __call__(self):
pass
Which will still be callable but just be a nullop.

How do I mock a superclass's __init__ create an attribute containing a mock object for a unit test?

I am attempting to write a unit test for a class's __init__:
def __init__(self, buildNum, configFile = "configfile.txt"):
super(DevBuild, self).__init__(buildNum, configFile)
if configFile == "configfile.txt":
self.config.MakeDevBuild()
The config attribute is set by the super's __init__. I'm using mock, and I want the config attribute to be a mock object. However, I haven't been able to figure out how to actually make that happen. Here's the best I could come up with for the test:
def test_init(self):
with patch('DevBuild.super', create=True) as mock_super:
mock_MakeDevBuild = MagicMock()
mock_super.return_value.config.MakeDevBuild = mock_MakeDevBuild
# Test with manual configuration
self.testBuild = DevBuild("42", "devconfigfile.txt")
self.assertFalse(mock_MakeDevBuild.called)
# Test with automated configuration
self.testBuild = DevBuild("42")
mock_MakeDevBuild.assert_called_once_with()
However, this doesn't work--I get an error:
Error
Traceback (most recent call last):
File "/Users/khagler/Projects/BuildClass/BuildClass/test_devBuild.py", line 17, in test_init
self.testBuild = DevBuild("42")
File "/Users/khagler/Projects/BuildClass/BuildClass/DevBuild.py", line 39, in __init__
self.config.MakeDevBuild()
AttributeError: 'DevBuild' object has no attribute 'config'
Clearly I'm not setting the config attribute correctly, but I have no idea where exactly I should be setting it. Or for that matter, if what I want to do is even possible. Can anyone tell me what I need to do to make this work?
You can't mock __init__ by setting it directly - see _unsupported_magics in mock.py.
As for what you can do, you can mock __init__ by passing it to patch, like so:
mock_makeDevBuild = MagicMock()
def mock_init(self, buildNum, configFile):
self.config = MagicMock()
self.config.MakeDevBuild = mock_makeDevBuild
with patch('DevBuild.SuperDevBuild.__init__', new=mock_init):
DevBuild("42")
mock_makeDevBuild.assert_called_once_with()
where SuperDevBuild is a base class of DevBuild.
If you really want to mock super(), you can perhaps make a class and then bind __init__ to object manually, like
mock_makeDevBuild = MagicMock()
def get_mock_super(tp, obj):
class mock_super(object):
#staticmethod
def __init__(buildNum, configFile):
obj.config = MagicMock()
obj.config.MakeDevBuild = mock_makeDevBuild
return mock_super
with patch('DevBuild.super', create=True, new=get_mock_super):
DevBuild("42")
mock_makeDevBuild.assert_called_once_with()
which works, but is quite ugly..
I do it this way, mocking the inherited class init:
from unittest import mock
#mock.patch.object(HierarchicalConf, "__init__")
def test_super_init(self, mock_super_init):
# act
ConfigurationService('my_args')
# assert
mock_super_init.assert_called_once_with(args)
Given the class:
class ConfigurationService(HierarchicalConf):
def __init__(self, dag_name) -> None:
"""Wrapper of Hierarchical Conf."""
# ... my code
super().__init__(args)
And if you want to also mock the ConfigurationService init, you can do quite the same:
#mock.patch.object(ConfigurationService, "__init__")
def test_init(self, mock_init):
# act
ConfigurationService('my_args')
# assert
mock_init.assert_called_once_with('my_args')

python 2.6 exceptions.TypeError: unbound method _init_() ESMTP client instance

I am a completely new user to Python and BuildBot. Currently I am using an e-mail alert
when the BuildBot build status changes (moves from success to fail, or vice versa), and failing will e-mail every time there is a failed build. I am encountering the following Python error when sending an email is attempted.
--- <exception caught here> ---
**ESMTPClient.__init__(self, secret, contextFactory, *args, **kw)
exceptions.TypeError?: unbound method init() must be called with ESMTPClient
instance as first argument (got ESMTPSender instance instead)**
I have found some examples of this error online when searching for an answer, including
You just need to pass 'self' as an argument to 'Thread.init' and
calling the super class
but I am still unsure why there is an error. I would appreciate any guidance/help on why this error has occurred and how to go about resolving the issue. I am not the author of this code so I am unsure of what to be looking for to solve the problem.
The email was working before the following code was changed from gmail account to company account.
c['status'].append(mail.MailNotifier(
fromaddr="load.builder#company.co.uk",
extraRecipients=["example#company.com",
],
sendToInterestedUsers=False,
mode=('change', 'failing'),
relayhost="smtp.company.lan",
useTls=True,
smtpUser="lbuilder",
smtpPassword="password"))
Here's the block of code producing the exception:
class ESMTPSender(SenderMixin, ESMTPClient):
requireAuthentication = True
requireTransportSecurity = True
def __init__(self, username, secret, contextFactory=None, *args, **kw):
self.heloFallback = 0
self.username = username
if contextFactory is None:
contextFactory = self._getContextFactory()
ESMTPClient.__init__(self, secret, contextFactory, *args, **kw)
self._registerAuthenticators()
SSA
This seems like it would be a difficult exception to come by -- Generally you don't call __init__ explicitly unless you're inheriting from some other class. Here's one situation where you could get that error:
class Foo(object):
def __init__(self,*args):
print("In Foo, args:",args,type(self))
class Bar(object):
def __init__(self,*args):
Foo.__init__(self,*args) #Doesn't work. Complains that the object isn't the right type.
To fix this, we can make Bar inherit from Foo:
class Bar(Foo):
#^ Bar now inherits from Foo
def __init__(self,*args):
Foo.__init__(self,*args) #This will work now since a Bar instance is a Foo instance
If it doesn't make sense to have Bar subclassed from Foo, you can factor the common code out into a separate function:
def common_code(instance,*args):
print("Common code: args",args,type(instance))
class Foo(object):
def __init__(self,*args):
common_code(self,*args)
class Bar(object):
def __init__(self,*args):
common_code(self,*args)
Although this kind of problem can be difficult to diagnose without actually seeing the code which produces the error.

proper way python mock __init__() method that returns a fake class

Trying to mock out calls to pyazure library for django testing, but I can't figure out how to mock out the PyAzure class constructor so that it doesn't cause a TypeError. Is there a better way to approach mocking out an access library that generates a connection object?
Anything I've tried other than None generates a TypeError, which means I can't really even begin to test any of the PyAzure connection methods with actual return values. What is the best way to replace a working class with a fake class using mock?
Test Error:
======================================================================
ERROR: test_management_certificate_connect (azure_cloud.tests.ViewsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/bschott/Source/django-nimbis/apps/azure_cloud/tests.py", line 107, in test_management_certificate_connect
self.cert1.connect()
File "/Users/bschott/Source/django-nimbis/apps/azure_cloud/models.py", line 242, in connect
subscription_id=self.subscription.subscription_id)
TypeError: __init__() should return None, not 'FakeAzure'
----------------------------------------------------------------------
tests.py:
class ViewsTest(TestCase):
def setUp(self):
...
self.cert1 = ManagementCertificate.objects.create(
name="cert1",
subscription=self.subscription1,
management_cert=File(open(__file__), "cert1.pem"),
owner=self.user1)
...
class FakeAzure(object):
""" testing class for azure """
def list_services(self):
return ['service1', 'service2', 'service3']
def list_storages(self):
return ['storage1', 'storage2', 'storage3']
#mock.patch.object(pyazure.PyAzure, '__init__')
def test_management_certificate_connect(self, mock_pyazure_init):
mock_pyazure_init.return_value = self.FakeAzure()
self.cert1.connect()
assert mock_pyazure_init.called
models.py
class ManagementCertificate(models.Model):
# support connection caching to azure
_cached_connection = None
def connect(self):
"""
Connect to the management interface using these credentials.
"""
if not self._cached_connection:
self._cached_connection = pyazure.PyAzure(
management_cert_path=self.management_cert.path,
subscription_id=self.subscription.subscription_id)
logging.debug(self._cached_connection)
return self._cached_connection
You seem to have a misconception about what __init__() does. Its purpose is to initialise an instance that was already created earlier. The first argument to __init__() is self, which is the instance, so you can see it was already allocated when __init__() is called.
There is a method __new__() that is called before __init__() to create the actual instance. I think it would be much easier, though, to replace the whole class by a mock class, instead of mocking single methods.

Categories