I have models which contains lots of classmethods for filtering different kinds of data. Now the problem is, these classmethods are called in views for several functionality. For example, I have Order table as shown below:
class Order(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
total = models.DecimalField(max_digits=12, decimal_places=2, default=0)
order_date = models.DateTimeField(auto_now_add=True)
cancelled = models.BooleanField(default=False)
items = models.ManyToManyField(Items, through='OrderItems')
status = models.CharField(max_length=30, choices=choice_status, default='waiting')
restaurant = models.ForeignKey(Restaurant, on_delete=models.SET_NULL, related_name='orders', null=True)
razorpay_payment_id = models.CharField(max_length=100, null=True, blank=True)
razorpay_order_id = models.CharField(max_length=100, null=True, blank=True)
mode = models.CharField(max_length=10, choices=choice_mode, default='COD', null=True, blank=True)
paid = models.BooleanField(default=False, null=True, blank=True)
delivery_charges = models.DecimalField(max_digits=12, decimal_places=2, default=0)
user_address = models.TextField(max_length=500)
user_address_lat = models.DecimalField(max_digits=9, decimal_places=6)
user_address_long = models.DecimalField(max_digits=9, decimal_places=6)
restaurant_address = models.TextField(max_length=500)
restaurant_address_lat = models.DecimalField(max_digits=9, decimal_places=6)
restaurant_address_long = models.DecimalField(max_digits=9, decimal_places=6)
@classmethod
def get_order_with_search_params(cls, params, queryset):
search_order_id = None
with contextlib.suppress(ValueError):
search_order_id = int(params)
return queryset.filter(
Q(user__username__icontains=params) |
Q(restaurant__name__icontains=params) |
Q(id=search_order_id)
)
@classmethod
def get_order_from_status(cls, params, queryset):
return queryset.filter(Q(status=params.lower()))
@classmethod
def get_order_from_restaurant_id(cls, params, queryset):
restaurant_id = None
with contextlib.suppress(ValueError):
restaurant_id = int(params)
return queryset.filter(Q(restaurant_id=restaurant_id))
@classmethod
def get_object_from_pk(cls, pk):
return get_object_or_404(cls, pk=pk)
@classmethod
def get_total_of_all_orders(cls, queryset=None):
if not queryset:
queryset = cls.objects.all()
return queryset.filter(status='delivered').aggregate(total_sum=Sum('total'))['total_sum']
Now to test these functionality, I have to first have to do following:
register user (restaurant type)
activate this user
add Items to store with restaurant user
register another user (customer type)
activate this user too
add item to cart
place order
After placing order, it will create Order object, then I can test functionalities like filter. So this is integration testing.
Also along this steps, many related tables are affected like while registering users Address table will have been created, while adding items its CartItem table is populated, and many other things. This is the reason why I cannot just use Order.objects.create(**kwargs)
and then test classmethods
of model. Should I skip testing these classmethods? or their is any other ways to test these methods?
For ref.: I have only created testcases for fields and str methods shown below
def test_str_method(self):
obj = State.objects.create(name='TestState')
assert str(obj) == obj.name
def test_document_data(self, get_agent_document_form_initial_data):
agent = User.objects.create(
**{'username': 'test_agent1', 'mobile_number': ' 917894541211', 'email': '[email protected]'})
document_obj = Document.objects.create(agent=agent,
**get_agent_document_form_initial_data(pancard_document=filename,
license_document=filename))
assert document_obj.agent == agent
# assert document_obj.id == 1
assert document_obj.is_verified is False
assert document_obj.account_no == 1234567890
assert document_obj.ifsc_code == 'ABCD0123456'
assert document_obj.pancard_number == 'BNZAA2318J'
assert document_obj.ifsc_code == 'ABCD0123456'
assert document_obj.license_number == 'HR-0619850034761'
assert document_obj.pancard_document == './media/default.jpg'
assert document_obj.license_document == './media/default.jpg'
assert document_obj.razorpay_contact_id is None
assert document_obj.razorpay_fund_account_id is None
assert str(document_obj) == f'{document_obj.id} | {document_obj.agent} | {document_obj.is_verified}'
Just checking if values of fields are correct or not. But I want to write testcases for other methods in models which is related to flow of project.
CodePudding user response:
You can prepopulate data in Database, For better understanding, you can follow this link.
And then simply test your method shown below:
class TestOrderModelMethods:
def test_get_order_from_status(self):
assertQuerysetEqual(
Order.get_order_from_status(params='waiting', queryset=Order.objects.all()),
Order.objects.filter(status='waiting'),
ordered=False)