Cleanup / consolidate unit testing code (#4831)

- Move testing code out of helpers.py
- Create new file unit_test.py
This commit is contained in:
Oliver 2023-05-17 07:35:26 +10:00 committed by GitHub
parent f85b378115
commit 4785f465e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 138 additions and 139 deletions

View File

@ -6,7 +6,7 @@ Only used for testing the js files! - This file is omited from coverage.
import os # pragma: no cover
import pathlib # pragma: no cover
from InvenTree.helpers import InvenTreeTestCase # pragma: no cover
from InvenTree.unit_test import InvenTreeTestCase # pragma: no cover
class RenderJavascriptFiles(InvenTreeTestCase): # pragma: no cover

View File

@ -8,18 +8,15 @@ import os
import os.path
import re
from decimal import Decimal, InvalidOperation
from pathlib import Path
from wsgiref.util import FileWrapper
from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.staticfiles.storage import StaticFilesStorage
from django.core.exceptions import FieldError, ValidationError
from django.core.files.storage import default_storage
from django.core.validators import URLValidator
from django.db.utils import OperationalError, ProgrammingError
from django.http import StreamingHttpResponse
from django.test import TestCase
from django.utils.translation import gettext_lazy as _
import moneyed.localization
@ -36,7 +33,6 @@ from common.notifications import (InvenTreeNotificationBodies,
NotificationBody, trigger_notification)
from common.settings import currency_code_default
from .api_tester import ExchangeRateMixin, UserMixin
from .settings import MEDIA_URL, STATIC_URL
logger = logging.getLogger('inventree')
@ -850,75 +846,6 @@ def validateFilterString(value, model=None):
return results
def addUserPermission(user, permission):
"""Shortcut function for adding a certain permission to a user."""
perm = Permission.objects.get(codename=permission)
user.user_permissions.add(perm)
def addUserPermissions(user, permissions):
"""Shortcut function for adding multiple permissions to a user."""
for permission in permissions:
addUserPermission(user, permission)
def getMigrationFileNames(app):
"""Return a list of all migration filenames for provided app."""
local_dir = Path(__file__).parent
files = local_dir.joinpath('..', app, 'migrations').iterdir()
# Regex pattern for migration files
regex = re.compile(r"^[\d]+_.*\.py$")
migration_files = []
for f in files:
if regex.match(f.name):
migration_files.append(f.name)
return migration_files
def getOldestMigrationFile(app, exclude_extension=True, ignore_initial=True):
"""Return the filename associated with the oldest migration."""
oldest_num = -1
oldest_file = None
for f in getMigrationFileNames(app):
if ignore_initial and f.startswith('0001_initial'):
continue
num = int(f.split('_')[0])
if oldest_file is None or num < oldest_num:
oldest_num = num
oldest_file = f
if exclude_extension:
oldest_file = oldest_file.replace('.py', '')
return oldest_file
def getNewestMigrationFile(app, exclude_extension=True):
"""Return the filename associated with the newest migration."""
newest_file = None
newest_num = -1
for f in getMigrationFileNames(app):
num = int(f.split('_')[0])
if newest_file is None or num > newest_num:
newest_num = num
newest_file = f
if exclude_extension:
newest_file = newest_file.replace('.py', '')
return newest_file
def clean_decimal(number):
"""Clean-up decimal value."""
# Check if empty
@ -1091,11 +1018,6 @@ def inheritors(cls):
return subcls
class InvenTreeTestCase(ExchangeRateMixin, UserMixin, TestCase):
"""Testcase with user setup buildin."""
pass
def notify_responsible(instance, sender, content: NotificationBody = InvenTreeNotificationBodies.NewOrder, exclude=None):
"""Notify all responsible parties of a change in an instance.

View File

@ -6,8 +6,7 @@ from django.urls import reverse
from rest_framework import status
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeAPITestCase, InvenTreeTestCase
from users.models import RuleSet, update_group_roles

View File

@ -7,7 +7,7 @@ from django.urls import reverse
from error_report.models import Error
from InvenTree.exceptions import log_error
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
class MiddlewareTests(InvenTreeTestCase):

View File

@ -5,7 +5,7 @@ import os
from django.contrib.auth import get_user_model
from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
class ViewTests(InvenTreeTestCase):

View File

@ -24,6 +24,7 @@ import InvenTree.tasks
from common.models import InvenTreeSetting
from common.settings import currency_codes
from InvenTree.sanitizer import sanitize_svg
from InvenTree.unit_test import InvenTreeTestCase
from part.models import Part, PartCategory
from stock.models import StockItem, StockLocation
@ -711,7 +712,7 @@ class TestStatus(TestCase):
self.assertEqual(ready.isImportingData(), False)
class TestSettings(helpers.InvenTreeTestCase):
class TestSettings(InvenTreeTestCase):
"""Unit tests for settings."""
superuser = True
@ -850,7 +851,7 @@ class TestSettings(helpers.InvenTreeTestCase):
self.assertEqual(config.get_setting(TEST_ENV_NAME, None, typecast=dict), {})
class TestInstanceName(helpers.InvenTreeTestCase):
class TestInstanceName(InvenTreeTestCase):
"""Unit tests for instance name."""
def test_instance_name(self):
@ -878,7 +879,7 @@ class TestInstanceName(helpers.InvenTreeTestCase):
self.assertEqual(site_obj.domain, 'http://127.1.2.3')
class TestOffloadTask(helpers.InvenTreeTestCase):
class TestOffloadTask(InvenTreeTestCase):
"""Tests for offloading tasks to the background worker"""
fixtures = [
@ -975,7 +976,7 @@ class TestOffloadTask(helpers.InvenTreeTestCase):
self.assertTrue(result)
class BarcodeMixinTest(helpers.InvenTreeTestCase):
class BarcodeMixinTest(InvenTreeTestCase):
"""Tests for the InvenTreeBarcodeMixin mixin class"""
def test_barcode_model_type(self):

View File

@ -1,12 +1,14 @@
"""Helper functions for performing API unit tests."""
"""Helper functions for unit testing / CI"""
import csv
import io
import re
from pathlib import Path
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.contrib.auth.models import Group, Permission
from django.http.response import StreamingHttpResponse
from django.test import TestCase
from djmoney.contrib.exchange.models import ExchangeBackend, Rate
from rest_framework.test import APITestCase
@ -15,6 +17,75 @@ from plugin import registry
from plugin.models import PluginConfig
def addUserPermission(user, permission):
"""Shortcut function for adding a certain permission to a user."""
perm = Permission.objects.get(codename=permission)
user.user_permissions.add(perm)
def addUserPermissions(user, permissions):
"""Shortcut function for adding multiple permissions to a user."""
for permission in permissions:
addUserPermission(user, permission)
def getMigrationFileNames(app):
"""Return a list of all migration filenames for provided app."""
local_dir = Path(__file__).parent
files = local_dir.joinpath('..', app, 'migrations').iterdir()
# Regex pattern for migration files
regex = re.compile(r"^[\d]+_.*\.py$")
migration_files = []
for f in files:
if regex.match(f.name):
migration_files.append(f.name)
return migration_files
def getOldestMigrationFile(app, exclude_extension=True, ignore_initial=True):
"""Return the filename associated with the oldest migration."""
oldest_num = -1
oldest_file = None
for f in getMigrationFileNames(app):
if ignore_initial and f.startswith('0001_initial'):
continue
num = int(f.split('_')[0])
if oldest_file is None or num < oldest_num:
oldest_num = num
oldest_file = f
if exclude_extension:
oldest_file = oldest_file.replace('.py', '')
return oldest_file
def getNewestMigrationFile(app, exclude_extension=True):
"""Return the filename associated with the newest migration."""
newest_file = None
newest_num = -1
for f in getMigrationFileNames(app):
num = int(f.split('_')[0])
if newest_file is None or num > newest_num:
newest_num = num
newest_file = f
if exclude_extension:
newest_file = newest_file.replace('.py', '')
return newest_file
class UserMixin:
"""Mixin to setup a user and login for tests.
@ -337,3 +408,8 @@ class InvenTreeAPITestCase(ExchangeRateMixin, UserMixin, APITestCase):
data.append(entry)
return data
class InvenTreeTestCase(ExchangeRateMixin, UserMixin, TestCase):
"""Testcase with user setup buildin."""
pass

View File

@ -11,7 +11,7 @@ from build.models import Build, BuildItem
from stock.models import StockItem
from InvenTree.status_codes import BuildStatus, StockStatus
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
class TestBuildAPI(InvenTreeAPITestCase):

View File

@ -2,14 +2,14 @@
from django_test_migrations.contrib.unittest_case import MigratorTestCase
from InvenTree import helpers
from InvenTree import unit_test
class TestForwardMigrations(MigratorTestCase):
"""Test entire schema migration sequence for the build app."""
migrate_from = ('build', helpers.getOldestMigrationFile('build'))
migrate_to = ('build', helpers.getNewestMigrationFile('build'))
migrate_from = ('build', unit_test.getOldestMigrationFile('build'))
migrate_to = ('build', unit_test.getNewestMigrationFile('build'))
def prepare(self):
"""Create initial data!"""
@ -58,7 +58,7 @@ class TestForwardMigrations(MigratorTestCase):
class TestReferenceMigration(MigratorTestCase):
"""Test custom migration which adds 'reference' field to Build model."""
migrate_from = ('build', helpers.getOldestMigrationFile('build'))
migrate_from = ('build', unit_test.getOldestMigrationFile('build'))
migrate_to = ('build', '0018_build_reference')
def prepare(self):
@ -113,7 +113,7 @@ class TestReferencePatternMigration(MigratorTestCase):
"""
migrate_from = ('build', '0019_auto_20201019_1302')
migrate_to = ('build', helpers.getNewestMigrationFile('build'))
migrate_to = ('build', unit_test.getNewestMigrationFile('build'))
def prepare(self):
"""Create some initial data prior to migration"""

View File

@ -4,7 +4,7 @@ from django.urls import reverse
from datetime import datetime, timedelta
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
from .models import Build
from stock.models import StockItem

View File

@ -14,8 +14,9 @@ from django.urls import reverse
import PIL
from InvenTree.api_tester import InvenTreeAPITestCase, PluginMixin
from InvenTree.helpers import InvenTreeTestCase, str2bool
from InvenTree.helpers import str2bool
from InvenTree.unit_test import (InvenTreeAPITestCase, InvenTreeTestCase,
PluginMixin)
from plugin import registry
from plugin.models import NotificationUserSetting

View File

@ -4,7 +4,7 @@ from django.urls import reverse
from rest_framework import status
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
from .models import Company, Contact, SupplierPart

View File

@ -2,14 +2,14 @@
from django_test_migrations.contrib.unittest_case import MigratorTestCase
from InvenTree import helpers
from InvenTree import unit_test
class TestForwardMigrations(MigratorTestCase):
"""Unit testing class for testing 'company' app migrations"""
migrate_from = ('company', helpers.getOldestMigrationFile('company'))
migrate_to = ('company', helpers.getNewestMigrationFile('company'))
migrate_from = ('company', unit_test.getOldestMigrationFile('company'))
migrate_to = ('company', unit_test.getNewestMigrationFile('company'))
def prepare(self):
"""Create some simple Company data, and ensure that it migrates OK."""

View File

@ -2,7 +2,7 @@
from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
class CompanyViewTest(InvenTreeTestCase):

View File

@ -2,7 +2,7 @@
from django.urls import reverse
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
class TestReportTests(InvenTreeAPITestCase):

View File

@ -9,8 +9,8 @@ from django.core.files.base import ContentFile
from django.urls import reverse
from common.models import InvenTreeSetting
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.helpers import validateFilterString
from InvenTree.unit_test import InvenTreeAPITestCase
from part.models import Part
from stock.models import StockItem

View File

@ -15,10 +15,10 @@ from rest_framework import status
from common.settings import currency_codes
from company.models import Company
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.status_codes import (PurchaseOrderStatus, ReturnOrderLineStatus,
ReturnOrderStatus, SalesOrderStatus,
StockStatus)
from InvenTree.unit_test import InvenTreeAPITestCase
from order import models
from part.models import Part
from stock.models import StockItem

View File

@ -2,7 +2,7 @@
from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
class OrderViewTestCase(InvenTreeTestCase):

View File

@ -18,9 +18,9 @@ import company.models
import order.models
from common.models import InvenTreeSetting
from company.models import Company, SupplierPart
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
StockStatus)
from InvenTree.unit_test import InvenTreeAPITestCase
from part.models import (BomItem, BomItemSubstitute, Part, PartCategory,
PartCategoryParameterTemplate, PartParameterTemplate,
PartRelated, PartStocktake)

View File

@ -4,7 +4,7 @@ import csv
from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
class BomExportTest(InvenTreeTestCase):

View File

@ -5,7 +5,7 @@ from django.urls import reverse
import tablib
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
from part.models import Part

View File

@ -2,14 +2,14 @@
from django_test_migrations.contrib.unittest_case import MigratorTestCase
from InvenTree import helpers
from InvenTree import unit_test
class TestForwardMigrations(MigratorTestCase):
"""Test entire schema migration sequence for the part app."""
migrate_from = ('part', helpers.getOldestMigrationFile('part'))
migrate_to = ('part', helpers.getNewestMigrationFile('part'))
migrate_from = ('part', unit_test.getOldestMigrationFile('part'))
migrate_to = ('part', unit_test.getNewestMigrationFile('part'))
def prepare(self):
"""Create initial data."""
@ -52,7 +52,7 @@ class TestBomItemMigrations(MigratorTestCase):
"""Tests for BomItem migrations"""
migrate_from = ('part', '0002_auto_20190520_2204')
migrate_to = ('part', helpers.getNewestMigrationFile('part'))
migrate_to = ('part', unit_test.getNewestMigrationFile('part'))
def prepare(self):
"""Create intial dataset"""

View File

@ -14,7 +14,7 @@ from common.models import (InvenTreeSetting, InvenTreeUserSetting,
NotificationEntry, NotificationMessage)
from common.notifications import UIMessageNotification, storage
from InvenTree import version
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
from .models import (Part, PartCategory, PartCategoryStar, PartRelated,
PartStar, PartStocktake, PartTestTemplate,

View File

@ -10,8 +10,8 @@ import company.models
import order.models
import part.models
import stock.models
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.status_codes import PurchaseOrderStatus
from InvenTree.unit_test import InvenTreeTestCase
class PartPricingTests(InvenTreeTestCase):

View File

@ -2,7 +2,7 @@
from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
from .models import Part

View File

@ -2,7 +2,7 @@
from django.test import TestCase
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
from plugin import InvenTreePlugin
from plugin.mixins import ActionMixin

View File

@ -4,7 +4,7 @@ from django.urls import reverse
from rest_framework import status
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
from stock.models import StockItem

View File

@ -8,7 +8,7 @@ from django.urls import include, re_path, reverse
from error_report.models import Error
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
from plugin import InvenTreePlugin
from plugin.base.integration.mixins import PanelMixin
from plugin.helpers import MixinNotImplementedError

View File

@ -8,7 +8,7 @@ from django.urls import reverse
from PIL import Image
from common.models import InvenTreeSetting
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
from label.models import PartLabel, StockItemLabel, StockLocationLabel
from part.models import Part
from plugin.base.label.mixins import LabelPrintingMixin

View File

@ -2,7 +2,7 @@
from django.urls import reverse
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
from plugin import InvenTreePlugin, MixinNotImplementedError, registry
from plugin.base.locate.mixins import LocateMixin
from stock.models import StockItem, StockLocation

View File

@ -4,7 +4,7 @@ from django.urls import reverse
import part.models
import stock.models
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
class TestInvenTreeBarcode(InvenTreeAPITestCase):

View File

@ -1,6 +1,6 @@
"""Unit tests for action plugins."""
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
class SampleIntegrationPluginTests(InvenTreeTestCase):

View File

@ -1,6 +1,6 @@
"""Unit tests for action plugins."""
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
from plugin.samples.integration.simpleactionplugin import SimpleActionPlugin

View File

@ -2,7 +2,7 @@
from django.urls import reverse
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
from plugin import InvenTreePlugin, registry
from plugin.helpers import MixinNotImplementedError
from plugin.mixins import LocateMixin

View File

@ -4,7 +4,7 @@ from django.urls import reverse
from rest_framework.exceptions import NotFound
from InvenTree.api_tester import InvenTreeAPITestCase, PluginMixin
from InvenTree.unit_test import InvenTreeAPITestCase, PluginMixin
from plugin.api import check_plugin
from plugin.models import PluginConfig

View File

@ -16,7 +16,7 @@ from PIL import Image
import report.models as report_models
from build.models import Build
from common.models import InvenTreeSetting, InvenTreeUserSetting
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
from report.templatetags import barcode as barcode_tags
from report.templatetags import report as report_tags
from stock.models import StockItem, StockItemAttachment

View File

@ -16,8 +16,8 @@ from rest_framework import status
import company.models
import part.models
from common.models import InvenTreeSetting
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.status_codes import StockStatus
from InvenTree.unit_test import InvenTreeAPITestCase
from part.models import Part
from stock.models import StockItem, StockItemTestResult, StockLocation

View File

@ -2,14 +2,14 @@
from django_test_migrations.contrib.unittest_case import MigratorTestCase
from InvenTree import helpers
from InvenTree import unit_test
class TestSerialNumberMigration(MigratorTestCase):
"""Test data migration which updates serial numbers"""
migrate_from = ('stock', '0067_alter_stockitem_part')
migrate_to = ('stock', helpers.getNewestMigrationFile('stock'))
migrate_to = ('stock', unit_test.getNewestMigrationFile('stock'))
def prepare(self):
"""Create initial data for this migration"""
@ -73,7 +73,7 @@ class TestScheduledForDeletionMigration(MigratorTestCase):
"""Test data migration for removing 'scheduled_for_deletion' field"""
migrate_from = ('stock', '0066_stockitem_scheduled_for_deletion')
migrate_to = ('stock', helpers.getNewestMigrationFile('stock'))
migrate_to = ('stock', unit_test.getNewestMigrationFile('stock'))
def prepare(self):
"""Create some initial stock items"""

View File

@ -4,8 +4,8 @@ from django.contrib.auth.models import Group
from django.urls import reverse
from common.models import InvenTreeSetting
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.status_codes import StockStatus
from InvenTree.unit_test import InvenTreeTestCase
from stock.models import StockItem, StockLocation
from users.models import Owner

View File

@ -9,8 +9,8 @@ from django.test import override_settings
from build.models import Build
from common.models import InvenTreeSetting
from company.models import Company
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.status_codes import StockHistoryCode
from InvenTree.unit_test import InvenTreeTestCase
from order.models import SalesOrder
from part.models import Part

View File

@ -3,7 +3,7 @@
from django.contrib.auth.models import Group, User
from django.urls import reverse
from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.unit_test import InvenTreeAPITestCase
class UserAPITests(InvenTreeAPITestCase):

View File

@ -2,14 +2,14 @@
from django_test_migrations.contrib.unittest_case import MigratorTestCase
from InvenTree import helpers
from InvenTree import unit_test
class TestForwardMigrations(MigratorTestCase):
"""Test entire schema migration sequence for the users app."""
migrate_from = ('users', helpers.getOldestMigrationFile('users'))
migrate_to = ('users', helpers.getNewestMigrationFile('users'))
migrate_from = ('users', unit_test.getOldestMigrationFile('users'))
migrate_to = ('users', unit_test.getNewestMigrationFile('users'))
def prepare(self):
"""Setup the initial state of the database before migrations"""

View File

@ -7,7 +7,7 @@ from django.urls import reverse
from rest_framework.authtoken.models import Token
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.unit_test import InvenTreeTestCase
from users.models import Owner, RuleSet