Imported python class instance inheritance - python

Currently I'm inheriting from an external class and importing another one locally:
from locust.contrib.fasthttp import FastHttpUser
from local_helper import TaskDetails
class User_1(FastHttpUser):
#task
def iteration_task(self):
self.client.get(url)
I want to offload self.client.get(url) to TaskDetails,
What I want to achieve is something like this:
td = TaskDetails()
class User_1(FastHttpUser):
#task
td.client_get(url) # with included FastHttpUser methods from User_1 class
is it possible to do something like this?

Related

Django. How to create model instance in test db using objects fabric?

I want to make my unit tests setUp function clear from repeating tons of model creation lines like 1) create user 2) now create employee with fk to this user and etc.
In order to do that I've made a simple factory of dummy objects but I might've done some mistakes or just misunderstood something. Here's a piece of factory (dummy_data is just a bunch of dicts):
from abc import ABC
from users.models import User
from employees.models import Employee
from .dummy_data import(
user_data,
employee_data,
)
class DummyObjectFactory(ABC):
"""Fabric representing dummy test objects"""
def get_dummy_object(self):
"""Return dummy object"""
class DummyUser(DummyObjectFactory):
def get_dummy_object(self) -> User:
return User.objects.create_user(**user_data)
class DummyEmployee(DummyObjectFactory):
def get_dummy_object(self) -> Employee:
user = DummyUser().get_dummy_object()
return Employee.objects.create(**employee_data, user=user)
dummy_factory = {
"User": DummyUser().get_dummy_object(),
"Employee": DummyEmployee().get_dummy_object(),
}
dummy_factory = dot_dict(dummy_factory)
Then I make a dot notaion dictionary of all kinds of fabrics for easy calling them buy dummy_factory.Name . My intetion was that I call fabric with the desired model name and it creates it's instance.
The problem is: when I call it in some test's setUp method like so test_user = dummy_factory.User it creates object in actual database but I want it to be in test database.
Example of test:
class TestEmployeesListView(TestCase):
def setUp(self):
self.test_user = dummy_factory.User
self.test_employee = dummy_factory.Employee
self.client = Client()
def test_listview_deny_anonymous_user(self):
response = self.client.get(reverse('employees:employees-list'))
self.assertRedirects(response, '/login/?next=/employees/')
Yes, I've searched for the solution and found Factory boy and Faker libraries, but I want to complete my fabric, make it work properly. Thanks for your attention.
So I made it work. What I did was:
Added #abstractmethod decorator in the abstract class.
Every concrete factory methods must have a #classmethod decorator and recieve cls as an argument:
class DummyUser(DummyObjectFactory):
#classmethod
def get_dummy_object(cls) -> User:
return User.objects.create_user(**user_data)
It just work as intended: factory creates objects in test db. Thank you folks for participation.

Is there such a thing as an AbstractSubClass in python?

The background
In python, if you were defining an Abstract Base Class which requires that its methods be overwritten, you'd do:
from abc import ABC, abstractmethod
class MyAbstractClass(ABC):
#abstractmethod
def my_method(self):
pass
The following code would then fail because it doesn't implement my_method.
class MyConcreteClass(MyAbstractClass):
pass
But what if I want to define the method requirements of a mixin class?
class MyMixin:
def my_mixin_method(self):
self.a_required_method()
The following code is then valid:
class MyBase:
def a_required_method(self):
pass
class MyFull(MyMixin, MyBase):
pass
The following code is also valid...
class MyDubious(MyMixin):
pass
But exposes an error at runtime:
MyFull().my_mixin_method() # Works
MyDubious().my_mixin_method() # Runtime error
The Question
Is there something like AbstractBaseClass which can be added to Mixin classes, to ensure that a derived class can't be instantiated unless it inherits correctly?
I'm thinking a nice API would look like:
from asc import ASC, requiredmethod
class MyRobustMixin(ASC):
#requiredmethod
def a_required_method(self):
pass
def my_mixin_method(self):
self.a_required_method()

How do you correctly mock a 3rd-party module in Django

I'm trying to write a simple unit test to test an instance method of one of my models in Django. However my class initialises an external connection on __init__ which is not being patched even though I'm trying to target it.
Folder Structure:
- project/
- app1/
- tests/
- tests_models.py
- models.py
models.py:
from 3rdPartyPlugin import Bot
class MyClass:
def __init__(self, token):
self.bot = Bot(token)
def generate_buttons(self):
...
tests_models.py:
from django.test import TestCase
from unittest.mock import MagicMock, patch
from app1.models import MyClass
#patch('app1.models.3rdPartyPlugin.Bot')
class GenerateButtonsTestCase(TestCase):
def setUp(self):
self.tb = MyClass('', '', '')
def test_generates_button_correctly(self):
return True
I can't get past the setUp step because the initialisation of the class fails because it tries to reach out to that 3rdPartyPlugin module even though I patched it.
I've tried setting the patch to:
#patch('app1.models.3rdPartyPlugin.Bot')
#patch('app1.models.Bot')
#patch('app1.models.TB.Bot')
But all of the above still leads to the Bot being called. Any suggestions?
The problem is that Bot is already imported and read in models.py before you patch it.
Try to import the whole module instead:
import 3rdPartyPlugin
class MyClass:
def __init__(self, token):
self.bot = 3rdPartyPlugin.Bot(token)
def generate_buttons(self):
I eventually was able to solve this by moving the 3rdPartyPlugin code out of the initialiser and into an instance method on the class I was testing. This is how it looked in code:
models.py:
from 3rdPartyPlugin import Bot
class MyClass:
def __init__(self, token):
self.token = token
self.bot = self.bot()
def bot(self):
Bot(self.token)
tests_models.py:
from app1.models import MyClass
class GenerateButtonsTestCase(TestCase):
#patch('app1.models.MyClass.bot')
def setUp(self, _):
self.tb = MyClass('', '', '')
And after making the above changes, the patch correctly works and patches my use of Bot from the 3rdPartyPlugin. It's a bit messy but it works for me.

Inheriting setUp method Python Unittest

I have a question regarding unittest with Python! Let's say that I have a docker container set up that handles a specific api endpoint (let's say users, ex: my_site/users/etc/etc/etc). There are quite a few different layers that are broken up and handled for this container. Classes that handle the actual call and response, logic layer, data layer. I am wanting to write tests around the specific calls (just checking for status codes).
There are a lot of different classes that act as Handlers for the given endpoints. There are a few things that I would have to set up differently per one, however, each one inherits from Application and uses some methods from it. I am wanting to do a setUp class for my unittest so I don't have to re-establish this each time. Any advice will help. So far I've mainly seen that inheritance is a bad idea with testing, however, I am only wanting to use this for setUp. Here's an example:
class SetUpClass(unittest.TestCase):
def setUp(self):
self._some_data = data_set.FirstOne()
self._another_data_set = data_set.SecondOne()
def get_app(self):
config = Config()
return Application(config,
first_one=self._some_data,
second_one=self._another_data_set)
class TestFirstHandler(SetUpClass, unittest.TestCase):
def setUp(self):
new_var = something
def tearDown(self):
pass
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users')
self.assertEqual(res.code, 200)
class TestSecondHandler(SetUpClass, unittest.TestCase):
def setUp(self):
different_var_thats_specific_to_this_handler = something_else
def tearDown(self):
pass
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users/account/?something_custom={}'.format('WOW'))
self.assertEqual(res.code, 200)
Thanks again!!
As mentioned in the comments, you just need to learn how to use super(). You also don't need to repeat TestCase in the list of base classes.
Here's the simple version for Python 3:
class TestFirstHandler(SetUpClass):
def setUp(self):
super().setUp()
new_var = something
def tearDown(self): # Easier to not declare this if it's empty.
super().tearDown()
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users')
self.assertEqual(res.code, 200)

Python, Django, using Import from inside of a class, can't seem to figure this out

I want to use imports inside a class that is then inherited by another class so that I don't have to manually define my imports in each file. I am trying it like this but its not working, any advice is appreciated:
class Djangoimports ():
def __init__(self):
from django.template import Context
print Context
class Init1 (Djangoimports):
def __init__(self):
Djangoimports.__init__(self)
self.c = Context(self.constructor_dict) # just example of trying to use the imported "Context"
>>>>> global name 'Context' is not defined
I have tried variations of trying to use "self" but can't figure out how to appropriately use this with the import from as its not the same as a class attribute / method where I normally use 'self'
This works fine for me.
But you're better off doing this:
>>> class Test(object):
... from functools import partial
...
>>> Test().partial
<type 'functools.partial'>
Note that doing it your way, you have to initialize them on a per instance basis and assign to self, like so:
def Test(object):
def __init__(self):
from functools import partial
self.partial = partial
either way, you can now access bar in other methods on that class or a derived one as self.bar.
In Python, an import just adds to current namespace. The namespace is lost once you return from the function, but you can preserve the pointer appending it to 'self'.
You can do:
class Djangoimports ():
def __init__(self):
from django.template import Context
self.Context = Context
class Init1 (Djangoimports):
def __init__(self):
Djangoimports.__init__(self)
self.c = self.Context(self.constructor_dict)

Categories

Resources