RecursionError: when using factory boy - django

I can't use factory boy correctly.
That is my factories:
import factory
from harrispierce.models import Article, Journal, Section
class JournalFactory(factory.Factory):
class Meta:
model = Journal
name = factory.sequence(lambda n: 'Journal%d'%n)
#factory.post_generation
def sections(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
# A list of groups were passed in, use them
for section in extracted:
self.sections.add(section)
class SectionFactory(factory.Factory):
class Meta:
model = Section
name = factory.sequence(lambda n: 'Section%d'%n)
and my test:
import pytest
from django.test import TestCase, client
from harrispierce.factories import JournalFactory, SectionFactory
#pytest.mark.django_db
class TestIndex(TestCase):
#classmethod
def setUpTestData(cls):
cls.myclient = client.Client()
def test_index_view(self):
response = self.myclient.get('/')
assert response.status_code == 200
def test_index_content(self):
section0 = SectionFactory()
section1 = SectionFactory()
section2 = SectionFactory()
print('wijhdjk: ', section0)
journal1 = JournalFactory.create(sections=(section0, section1, section2))
response = self.myclient.get('/')
print('wijhdjk: ', journal1)
self.assertEquals(journal1.name, 'Section0')
self.assertContains(response, journal1.name)
But I get this when running pytest:
journal1 = JournalFactory.create(sections=(section0, section1, section2))
harrispierce_tests/test_index.py:22:
RecursionError: maximum recursion depth exceeded while calling a Python object
!!! Recursion detected (same locals & position)

One possible issue would be that you're not using the proper Factory base class: for a Django model, use factory.django.DjangoModelFactory.
This shouldn't cause the issue you have, though; a full stack trace would be useful.
Try to remove the #factory.post_generation section, and see whether you get a proper Journal object; then inspect what parameters where passed.
If this is not enough to fix your code, I suggest opening an issue on the factory_boy repository, with a reproducible test case (there are already some branches/commits attempting to reproduce a reported bug, which can be used as a template).

Related

Why does my Django test pass when it should fail?

I am new to testing of any sorts in coding. This is followup on this answer to my question. Answer establishes that this type of model method should not save object to database:
#classmethod
def create(cls, user, name):
list = cls(user=user, name=name)
return list
If this is the case I am curious why does this test pass and says everything is ok?
from django.test import TestCase
from .models import List
from django.contrib.auth.models import User
class ListTestCase(TestCase):
def setUp(self):
user_1 = User(username="test_user", password="abcd")
user_1.save()
List.objects.create(user=user_1, name="mylist")
List.objects.create(user=user_1, name="anotherlist")
def test_lists_is_created(self):
user_1 = User.objects.get(username="test_user")
list_1 = List.objects.get(user=user_1, name="mylist")
self.assertEqual("mylist", list_1.name)
The reason why the test passes is that you call a different method from the one that you've implemented.
The line in ListTestCase.setUp()
List.objects.create(user=user_1, name="mylist")
actually, call the Django's QuerySet.create() method. Notice that it's call via List.objects.create() not List.create(). Therefore, the object is saved in the database and the test passes.
In your case, you've implemented a method create() inside the List model, so you should call List.create().

How to fix django-oscar shipping UnboundLocalError?

I want to add a shipping methods to django-oscar, but I'm getting the UnboundLocalError error even though I've done everything on the document page.
Request Method: GET
Request URL: http://127.0.0.1:8000/checkout/shipping-address/
Django Version: 2.1.7
Exception Type: UnboundLocalError
Exception Value:
local variable 'methods' referenced before assignment
repository.py
from oscar.apps.shipping import repository
from . import methods
class Repository(repository.Repository):
def get_available_shipping_methods(self, basket, user=None, shipping_addr=None, request=None, **kwargs):
methods = (methods.Standard(),)
if shipping_addr and shipping_addr.country.code == 'GB':
# Express is only available in the UK
methods = (methods.Standard(), methods.Express())
return methods
methods.py
from oscar.apps.shipping import methods
from oscar.core import prices
from decimal import Decimal as D
class Standard(methods.Base):
code = 'standard'
name = 'Shipping (Standard)'
def calculate(self, basket):
return prices.Price(
currency=basket.currency,
excl_tax=D('5.00'), incl_tax=D('5.00'))
class Express(methods.Base):
code = 'express'
name = 'Shipping (Express)'
def calculate(self, basket):
return prices.Price(
currency=basket.currency,
excl_tax=D('4.00'), incl_tax=D('4.00'))
I can see that is in the docs, but they look to have a bug in them.
With UnboundLocalError you're essentially looking at a scope issue. A really simple example would be;
x = 10
def foo():
x += 1
print x
foo()
When foo executes x isn't available to foo. So change the import slightly to avoid this;
from oscar.apps.shipping import repository
from . import methods as shipping_methods
class Repository(repository.Repository):
def get_available_shipping_methods(self, basket, user=None, shipping_addr=None, request=None, **kwargs):
methods = (shipping_methods.Standard(),)
if shipping_addr and shipping_addr.country.code == 'GB':
# Express is only available in the UK
methods = (shipping_methods.Standard(), shipping_methods.Express())
return methods

How can i update class variable by calling a class method from a derived class

I am developing a package for my testing purpose called dbtest. This package is because i am using MySQLdb for connecting databases and hence it is very tedious task to write sql queries while testing. So i created a new package and all queries can be accessed with separate functions. I avoided django ORM because my database table have multiple foreign keys and primary keys.
Below present is a part of the package.
package.py
from django.test import TestCase
dbcon='connector'
class testcase(TestCase):
flag_user=[]
#classmethod
def setUpClass(cls):
global dbcon
dbcon=MySQLdb.connect(host=dbHost,port=dbPort,user=dbUser,passwd=dbPasswd,db=dbname)
super(testcase, cls).setUpClass()
cursor = dbcon.cursor()
sql=open("empty.sql").read()
cursor.execute(sql)
cursor.close()
views.MySQLdb=Mockdb()
#classmethod
def tearDownClass(cls):
dbcon.close()
def user_table(self,username=username,email=email):
cache=[username]
self.flag_user.append(cache)
cmpdata=(username,email)
insert_table(tablename_user,cmpdata)
def delete(self,table):
last_entry=self.flag_user[-1]
query_user = 'delete from USER where USERNAME=%s'
cursor=dbcon.cursor()
query=eval('query_%s'%table)
cursor.execute(query,last_entry)
dbcon.commit()
del self.flag_user[-1]
tests.py
from package import testcase
class showfiles(testcase):
def setUp(self):
print "setup2"
self.user_table(username='vishnu',email='vishnu#clartrum.com')
def tearDown(self):
print "teardown2"
self.delete("user")
def test_1(self):
print "test dbtest link feature"
def test_2(self):
print "test health/errorfiles with valid device"
self.user_table(username='vishnu',email='vishnu#clartrum.com')
The insert_table in package execute insert operation in sql and delete method deletes the last entry from user. empty.sql creates tables for the database.
Actually when i run the tests, finally the flag_user should contain only [['vishnu']]. But i get [['vishnu'],['vishnu']] and this is because delete function in teardown doesn't updating the value.
I think this is due to class instances ? Am i right or not?
Here :
class testcase(TestCase):
flag_user=[]
you create flag_user as a class attribute (shared by all instances).
Then here:
def user_table(self,username=username,email=email):
cache=[username]
self.flag_user.append(cache)
You append to the (class level) flag_user attribute (it's accessed thru the instance but it's still the class attribute)
But here:
def delete(self,table):
delete_table(tablename)
self.flag_user=[]
you create a flag_user attribute on the instance itself, which is totally disconnected from the eponym class attribute.
The simplest solution is to use an instance attribute right from the start instead of using a class attribute:
# package.py
from django.test import TestCase
dbcon='connector'
class testcase(TestCase):
def setUp(self):
self.flag_user = []
and don't forget to call testcase.setUp in child classes:
# tests.py
from package import testcase
class showfiles(testcase):
def setUp(self):
super(showfile, self).setUp()
self.user_table(username='vishnu',email='vishnu#clartrum.com')
The alternative solution if you really want a class attribute (I can't imagine why you would but...) is to modify testcase.delete() so it really clears the flag_user class attribute instead of creating an instance attribute, which is done by explicitely asking python to rebind the attribute on the class itself (type(obj) returns obj.__class__ which is the class the instance belongs to):
def delete(self,table):
delete_table(tablename)
type(self).flag_user = []

Only lists and tuples may be used in a list field Validation Error

Hi I am implementing test cases for my models.
I am using Mongoengine0.9.0 + Django 1.8
My models.py
class Project(Document):
# commented waiting for org-group to get finalize
project_name = StringField()
org_group = ListField(ReferenceField(OrganizationGroup, required=False))
My Serializers.py
class ProjectSerializer(DocumentSerializer):
class Meta:
model = Project
depth = 1
test.py file
def setUp(self):
# Every test needs access to the request factory.
self.factory = RequestFactory()
self.user = User.objects.create_user(
username='jacob', email='jacob#jacob.com', password='top_secret')
def test_post_put_project(self):
"""
Ensure we can create new clients in mongo database.
"""
org_group = str((test_utility.create_organization_group(self)).id)
url = '/project-management/project/'
data = {
"project_name": "googer",
"org_group": [org_group],
}
##import pdb; pdb.set_trace()
factory = APIRequestFactory()
user = User.objects.get(username='jacob')
view = views.ProjectList.as_view()
# Make an authenticated request to the view...
request = factory.post(url, data=data,)
force_authenticate(request, user=user)
response = view(request)
self.assertEqual(response.status_code, 200)
When I am running test cases I am getting this error
(Only lists and tuples may be used in a list field: ['org_group'])
The complete Stack Trace is
ValidationError: Got a ValidationError when calling Project.objects.create().
This may be because request data satisfies serializer validations but not Mongoengine`s.
You may need to check consistency between Project and ProjectSerializer.
If that is not the case, please open a ticket regarding this issue on https://github.com/umutbozkurt/django-rest-framework-mongoengine/issues
Original exception was: ValidationError (Project:None) (Only lists and tuples may be used in a list field: ['org_group'])
Not getting why we cant pass object like this.
Same thing when I am posting as an request to same method It is working for me but test cases it is failing
The tests should be running using multipart/form-data, which means that they don't support lists or nested data.
You can override this with the format argument, which I'm guessing you probably want to set to json. Most likely your front-end is using JSON, or a parser which supports lists, which explains why you are not seeing this.

Unit testing twisted.web.client.Agent's without the network

I've not done any twisted now for a couple of years and have started using the newer Agent style of client http calls. Using Agent has been OK, but testing is confusing me (it's twisted after all).
I've been through the https://twistedmatrix.com/documents/current/core/howto/trial.html docs and the APIs on trial tools and Agent itself. Also numerous searches.
I've gone with faking out Agent, as I don't need to test that. But then because of the steps to handle the processing and response of an Agent request, my test code has got nasty, implementing the nested layers of the Agent, protocol, etc. Where should I draw the line here and are there some utils I haven't found?
Here's a minimal example (naive implementation of SUT):
from twisted.web.client import Agent, readBody
from twisted.internet import reactor
import json
class SystemUnderTest(object):
def __init__(self, url):
self.url = url
def action(self):
d = self._makeAgent().request("GET", self.url)
d.addCallback(self._cbSuccess)
return d
def _makeAgent(self):
''' It's own method so can be overridden in tests '''
return Agent(reactor)
def _cbSuccess(self, response):
d = readBody(response)
d.addCallback(self._cbParse)
return d
def _cbParse(self, data):
self.result = json.loads(data)
print self.result
with the test module:
from twisted.trial import unittest
from sut import SystemUnderTest
from twisted.internet import defer
from twisted.test import proto_helpers
class Test(unittest.TestCase):
def test1(self):
s_u_t = ExtendedSystemUnderTest(None)
d = s_u_t.action()
d.addCallback(self._checks, s_u_t)
return d
def _checks(self, result, s_u_t):
print result
self.assertEqual({'one':1}, s_u_t.result)
class ExtendedSystemUnderTest(SystemUnderTest):
def _makeAgent(self):
return FakeSuccessfulAgent("{'one':1}")
## Getting ridiculous below here...
class FakeReason(object):
def check(self, _):
return False
def __str__(self):
return "It's my reason"
class FakeResponse(object):
''' Implementation of IResponse '''
def __init__(self, content):
self.content = content
self.prot = proto_helpers.StringTransport()
self.code = 200
self.phrase = ''
def deliverBody(self, prot):
prot.makeConnection(self.prot)
prot.dataReceived(self.content)
# reason = FakeReason()
# prot.connectionLost(reason)
class FakeSuccessfulAgent(object):
''' Implementation of IAgent '''
def __init__(self, response):
self.response = response
def request(self, method, url):
return defer.succeed(FakeResponse(self.response))
but testing is confusing me (it's twisted after all).
Hilarious.
class ExtendedSystemUnderTest(SystemUnderTest):
def _makeAgent(self):
return FakeSuccessfulAgent("{'one':1}")
I suggest you make the agent to use a normal parameter. This is more convenient than a private method like _makeAgent. Composition is great. Inheritance is meh.
class FakeReason(object):
...
There's no reason to make a fake of this. Just use twisted.python.failure.Failure. You don't have to fake every object in the test. Just the ones that get in your way if you don't fake them.
class FakeResponse(object):
...
This is likely good and necessary.
class FakeSuccessfulAgent(object):
...
This is most likely necessary as well. You should make it actually be more like an IAgent implementation though - declare that it implements the interface, use zope.interface.verify.verify{Class,Object} to make sure you get the implementation write, etc (eg request has the wrong signature now).
There's actually a ticket for adding all of these testing tools to Twisted itself - https://twistedmatrix.com/trac/ticket/4024. So I don't think you're actually confused, you're basically on the same track as the project itself. You're just suffering from the fact that Twisted hasn't already done all of this work for you.
Also, note that instead of:
class Test(unittest.TestCase):
def test1(self):
s_u_t = ExtendedSystemUnderTest(None)
d = s_u_t.action()
d.addCallback(self._checks, s_u_t)
return d
You can write something like this instead (and it is preferable):
class Test(unittest.TestCase):
def test1(self):
s_u_t = ExtendedSystemUnderTest(None)
d = s_u_t.action()
self._checks(s_u_t, self.successResultOf(d))
This is because your fake implementation of IAgent is synchronous. You know it is synchronous. By the time request returns, the Deferred it is returning has a result already. Writing the test this way means you can simplify your code a bit (ie, you can ignore the asynchronousness of it to some extent - because it isn't) and it avoids running the global reactor which is what returning a Deferred from a test method in trial does.