Merge pull request #1700 from SchrodingersGat/api-default-values

Unit testing for default values
This commit is contained in:
Oliver 2021-06-27 09:01:01 +10:00 committed by GitHub
commit 9e720ea620
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 144 additions and 10 deletions

View File

@ -18,6 +18,7 @@ class InvenTreeAPITestCase(APITestCase):
email = 'test@testing.com'
superuser = False
is_staff = True
auto_login = True
# Set list of roles automatically associated with the user
@ -40,6 +41,10 @@ class InvenTreeAPITestCase(APITestCase):
if self.superuser:
self.user.is_superuser = True
if self.is_staff:
self.user.is_staff = True
self.user.save()
for role in self.roles:

View File

@ -2,17 +2,19 @@
Serializers used in various InvenTree apps
"""
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError as DjangoValidationError
from rest_framework import serializers
from rest_framework.utils import model_meta
from rest_framework.fields import empty
from rest_framework.exceptions import ValidationError
@ -42,6 +44,72 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
but also ensures that the underlying model class data are checked on validation.
"""
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
# If instance is None, we are creating a new instance
if instance is None:
if data is empty:
data = OrderedDict()
else:
# Required to side-step immutability of a QueryDict
data = data.copy()
# Add missing fields which have default values
ModelClass = self.Meta.model
fields = model_meta.get_field_info(ModelClass)
for field_name, field in fields.fields.items():
if field.has_default() and field_name not in data:
value = field.default
# Account for callable functions
if callable(value):
try:
value = value()
except:
continue
data[field_name] = value
super().__init__(instance, data, **kwargs)
def get_initial(self):
"""
Construct initial data for the serializer.
Use the 'default' values specified by the django model definition
"""
initials = super().get_initial()
# Are we creating a new instance?
if self.instance is None:
ModelClass = self.Meta.model
fields = model_meta.get_field_info(ModelClass)
for field_name, field in fields.fields.items():
if field.has_default() and field_name not in initials:
value = field.default
# Account for callable functions
if callable(value):
try:
value = value()
except:
continue
initials[field_name] = value
return initials
def run_validation(self, data=empty):
""" Perform serializer validation.
In addition to running validators on the serializer fields,

View File

@ -13,6 +13,7 @@ from InvenTree.status_codes import StockStatus
from part.models import Part, PartCategory
from stock.models import StockItem
from company.models import Company
from common.models import InvenTreeSetting
class PartAPITest(InvenTreeAPITestCase):
@ -311,6 +312,59 @@ class PartAPITest(InvenTreeAPITestCase):
self.assertEqual(len(data['results']), n)
def test_default_values(self):
"""
Tests for 'default' values:
Ensure that unspecified fields revert to "default" values
(as specified in the model field definition)
"""
url = reverse('api-part-list')
response = self.client.post(url, {
'name': 'all defaults',
'description': 'my test part',
'category': 1,
})
data = response.data
# Check that the un-specified fields have used correct default values
self.assertTrue(data['active'])
self.assertFalse(data['virtual'])
# By default, parts are not purchaseable
self.assertFalse(data['purchaseable'])
# Set the default 'purchaseable' status to True
InvenTreeSetting.set_setting(
'PART_PURCHASEABLE',
True,
self.user
)
response = self.client.post(url, {
'name': 'all defaults',
'description': 'my test part 2',
'category': 1,
})
# Part should now be purchaseable by default
self.assertTrue(response.data['purchaseable'])
# "default" values should not be used if the value is specified
response = self.client.post(url, {
'name': 'all defaults',
'description': 'my test part 2',
'category': 1,
'active': False,
'purchaseable': False,
})
self.assertFalse(response.data['active'])
self.assertFalse(response.data['purchaseable'])
class PartDetailTests(InvenTreeAPITestCase):
"""
@ -392,6 +446,13 @@ class PartDetailTests(InvenTreeAPITestCase):
# Try to remove the part
response = self.client.delete(url)
# As the part is 'active' we cannot delete it
self.assertEqual(response.status_code, 405)
# So, let's make it not active
response = self.patch(url, {'active': False}, expected_code=200)
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
# Part count should have reduced
@ -542,8 +603,6 @@ class PartDetailTests(InvenTreeAPITestCase):
# And now check that the image has been set
p = Part.objects.get(pk=pk)
print("Image:", p.image.file)
class PartAPIAggregationTest(InvenTreeAPITestCase):
"""

View File

@ -354,15 +354,17 @@ class StockItemTest(StockAPITestCase):
self.assertContains(response, 'does not exist', status_code=status.HTTP_400_BAD_REQUEST)
# POST without quantity
response = self.client.post(
response = self.post(
self.list_url,
data={
{
'part': 1,
'location': 1,
}
},
expected_code=201,
)
self.assertContains(response, 'This field is required', status_code=status.HTTP_400_BAD_REQUEST)
# Item should have been created with default quantity
self.assertEqual(response.data['quantity'], 1)
# POST with quantity and part and location
response = self.client.post(