From 6d803d48b5f0e7ccf4a7ced19d2a90aa35f1b3dc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 May 2019 22:58:55 +1000 Subject: [PATCH 1/9] Add fixtures to the part test - Make development of further tests much easier --- InvenTree/part/fixtures/category.yaml | 56 +++++++++++++ InvenTree/part/fixtures/part.yaml | 32 +++++++ InvenTree/part/test_category.py | 116 ++++++++++++++++---------- 3 files changed, 161 insertions(+), 43 deletions(-) create mode 100644 InvenTree/part/fixtures/category.yaml create mode 100644 InvenTree/part/fixtures/part.yaml diff --git a/InvenTree/part/fixtures/category.yaml b/InvenTree/part/fixtures/category.yaml new file mode 100644 index 0000000000..7587cfdbc4 --- /dev/null +++ b/InvenTree/part/fixtures/category.yaml @@ -0,0 +1,56 @@ +# Create some PartCategory objects + +- model: part.partcategory + pk: 1 + fields: + name: Electronics + description: Electronic components + parent: null + default_location: null +- model: part.partcategory + pk: 2 + fields: + name: Resistors + description: Resistors + parent: 1 + default_location: null +- model: part.partcategory + pk: 3 + fields: + name: Capacitors + description: Capacitors + parent: 1 + default_location: null +- model: part.partcategory + pk: 4 + fields: + name: IC + description: Integrated Circuits + parent: 1 + default_location: null +- model: part.partcategory + pk: 5 + fields: + name: MCU + description: Microcontrollers + parent: 4 + default_location: null +- model: part.partcategory + pk: 6 + fields: + name: Transceivers + description: Communication interfaces + parent: 4 + default_location: null +- model: part.partcategory + pk: 7 + fields: + name: Mechanical + description: Mechanical componenets + default_location: null +- model: part.partcategory + pk: 8 + fields: + name: Fasteners + description: Screws, bolts, etc + parent: 7 diff --git a/InvenTree/part/fixtures/part.yaml b/InvenTree/part/fixtures/part.yaml new file mode 100644 index 0000000000..944f959eb8 --- /dev/null +++ b/InvenTree/part/fixtures/part.yaml @@ -0,0 +1,32 @@ +# Create some fasteners + +- model: part.part + fields: + name: 'M2x4 LPHS' + description: 'M2x4 low profile head screw' + category: 8 +- model: part.part + fields: + name: 'M3x12 SHCS' + description: 'M3x12 socket head cap screw' + category: 8 + +# Create some resistors + +- model: part.part + fields: + name: 'R_2K2_0805' + description: '2.2kOhm resistor in 0805 package' + category: 2 +- model: part.part + fields: + name: 'R_4K7_0603' + description: '4.7kOhm resistor in 0603 package' + category: 2 + +# Create some capacitors +- model: part.part + fields: + name: 'C_22N_0805' + description: '22nF capacitor in 0805 package' + category: 3 \ No newline at end of file diff --git a/InvenTree/part/test_category.py b/InvenTree/part/test_category.py index 3b732f80e8..be6a578b23 100644 --- a/InvenTree/part/test_category.py +++ b/InvenTree/part/test_category.py @@ -6,71 +6,101 @@ from .models import Part, PartCategory class CategoryTest(TestCase): """ Tests to ensure that the relational category tree functions correctly. + + Loads the following test fixtures: + - category.yaml """ + fixtures = [ + 'category', + 'part', + ] def setUp(self): - self.p1 = PartCategory.objects.create(name='A', - description='Most highest level', - parent=None) - - self.p2 = PartCategory.objects.create(name='B', - description='Sits under second', - parent=self.p1) - - self.p3 = PartCategory.objects.create(name='C', - description='Third tier category', - parent=self.p2) - - # Add two parts in p2 - Part.objects.create(name='Flange', category=self.p2) - Part.objects.create(name='Flob', category=self.p2) - - # Add one part in p3 - Part.objects.create(name='Blob', category=self.p3) + # Extract some interesting categories for time-saving + self.electronics = PartCategory.objects.get(name='Electronics') + self.mechanical = PartCategory.objects.get(name='Mechanical') + self.resistors = PartCategory.objects.get(name='Resistors') + self.capacitors = PartCategory.objects.get(name='Capacitors') + self.fasteners = PartCategory.objects.get(name='Fasteners') + self.ic = PartCategory.objects.get(name='IC') + self.transceivers = PartCategory.objects.get(name='Transceivers') def test_parents(self): - self.assertEqual(self.p1.parent, None) - self.assertEqual(self.p2.parent, self.p1) - self.assertEqual(self.p3.parent, self.p2) + """ Test that the parent fields are properly set, + based on the test fixtures """ + + self.assertEqual(self.resistors.parent, self.electronics) + self.assertEqual(self.capacitors.parent, self.electronics) + self.assertEqual(self.electronics.parent, None) + + self.assertEqual(self.fasteners.parent, self.mechanical) def test_children_count(self): - self.assertEqual(self.p1.has_children, True) - self.assertEqual(self.p2.has_children, True) - self.assertEqual(self.p3.has_children, False) + """ Test that categories have the correct number of children """ + + self.assertTrue(self.electronics.has_children) + self.assertTrue(self.mechanical.has_children) + + self.assertEqual(len(self.electronics.children.all()), 3) + self.assertEqual(len(self.mechanical.children.all()), 1) def test_unique_childs(self): - childs = self.p1.getUniqueChildren() + """ Test the 'unique_children' functionality """ - self.assertIn(self.p2.id, childs) - self.assertIn(self.p3.id, childs) + childs = self.electronics.getUniqueChildren() + + self.assertIn(self.transceivers.id, childs) + self.assertIn(self.ic.id, childs) + + self.assertNotIn(self.fasteners.id, childs) def test_unique_parents(self): - parents = self.p2.getUniqueParents() + """ Test the 'unique_parents' functionality """ + + parents = self.transceivers.getUniqueParents() - self.assertIn(self.p1.id, parents) + self.assertIn(self.electronics.id, parents) + self.assertIn(self.ic.id, parents) + self.assertNotIn(self.fasteners.id, parents) def test_path_string(self): - self.assertEqual(str(self.p3), 'A/B/C') + """ Test that the category path string works correctly """ + + self.assertEqual(str(self.resistors), 'Electronics/Resistors') + self.assertEqual(str(self.transceivers), 'Electronics/IC/Transceivers') def test_url(self): - self.assertEqual(self.p1.get_absolute_url(), '/part/category/1/') + """ Test that the PartCategory URL works """ + + self.assertEqual(self.capacitors.get_absolute_url(), '/part/category/3/') def test_part_count(self): - # No direct parts in the top-level category - self.assertEqual(self.p1.has_parts, False) - self.assertEqual(self.p2.has_parts, True) - self.assertEqual(self.p3.has_parts, True) + """ Test that the Category part count works """ - self.assertEqual(self.p1.partcount, 3) - self.assertEqual(self.p2.partcount, 3) - self.assertEqual(self.p3.partcount, 1) + self.assertTrue(self.resistors.has_parts) + self.assertTrue(self.fasteners.has_parts) + self.assertFalse(self.transceivers.has_parts) + + self.assertEqual(self.fasteners.partcount, 2) + self.assertEqual(self.capacitors.partcount, 1) def test_delete(self): - self.assertEqual(Part.objects.filter(category=self.p1).count(), 0) + """ Test that category deletion moves the children properly """ - # Delete p2 (it has 2 direct parts and one child category) - self.p2.delete() + # Delete the 'IC' category and 'Transceiver' should move to be under 'Electronics' + self.assertEqual(self.transceivers.parent, self.ic) + self.assertEqual(self.ic.parent, self.electronics) - self.assertEqual(Part.objects.filter(category=self.p1).count(), 2) + self.ic.delete() - self.assertEqual(PartCategory.objects.get(pk=self.p3.id).parent, self.p1) + # Get the data again + transceivers = PartCategory.objects.get(name='Transceivers') + self.assertEqual(transceivers.parent, self.electronics) + + # Now delete the 'fasteners' category - the parts should move to 'mechanical' + self.fasteners.delete() + + fasteners = Part.objects.filter(description__contains='screw') + + for f in fasteners: + self.assertEqual(f.category, self.mechanical) From ab6673caa3965f1db8a69d3cac87ed343aa87d26 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 May 2019 23:20:59 +1000 Subject: [PATCH 2/9] Add tests for default location traversal --- InvenTree/part/fixtures/category.yaml | 3 ++- InvenTree/part/fixtures/part.yaml | 9 +++++++- InvenTree/part/test_category.py | 23 +++++++++++++++++++ InvenTree/stock/fixtures/location.yaml | 31 ++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 InvenTree/stock/fixtures/location.yaml diff --git a/InvenTree/part/fixtures/category.yaml b/InvenTree/part/fixtures/category.yaml index 7587cfdbc4..86675a7fa9 100644 --- a/InvenTree/part/fixtures/category.yaml +++ b/InvenTree/part/fixtures/category.yaml @@ -6,7 +6,7 @@ name: Electronics description: Electronic components parent: null - default_location: null + default_location: 1 # Home - model: part.partcategory pk: 2 fields: @@ -54,3 +54,4 @@ name: Fasteners description: Screws, bolts, etc parent: 7 + default_location: 5 diff --git a/InvenTree/part/fixtures/part.yaml b/InvenTree/part/fixtures/part.yaml index 944f959eb8..dc9b17092a 100644 --- a/InvenTree/part/fixtures/part.yaml +++ b/InvenTree/part/fixtures/part.yaml @@ -23,10 +23,17 @@ name: 'R_4K7_0603' description: '4.7kOhm resistor in 0603 package' category: 2 + default_location: 2 # Home/Bathroom # Create some capacitors - model: part.part fields: name: 'C_22N_0805' description: '22nF capacitor in 0805 package' - category: 3 \ No newline at end of file + category: 3 + +- model: part.part + fields: + name: 'Widget' + description: 'A watchamacallit' + category: 7 \ No newline at end of file diff --git a/InvenTree/part/test_category.py b/InvenTree/part/test_category.py index be6a578b23..f2a88c8eb9 100644 --- a/InvenTree/part/test_category.py +++ b/InvenTree/part/test_category.py @@ -13,6 +13,7 @@ class CategoryTest(TestCase): fixtures = [ 'category', 'part', + 'location', ] def setUp(self): @@ -104,3 +105,25 @@ class CategoryTest(TestCase): for f in fasteners: self.assertEqual(f.category, self.mechanical) + + def test_default_locations(self): + """ Test traversal for default locations """ + + self.assertEqual(str(self.fasteners.default_location), 'Office/Drawer') + + # Test that parts in this location return the same default location, too + for p in self.fasteners.children.all(): + self.assert_equal(p.get_default_location(), 'Office/Drawer') + + # Any part under electronics should default to 'Home' + R1 = Part.objects.get(name='R_2K2_0805') + self.assertIsNone(R1.default_location) + self.assertEqual(R1.get_default_location().name, 'Home') + + # But one part has a default_location set + R2 = Part.objects.get(name='R_4K7_0603') + self.assertEqual(R2.get_default_location().name, 'Bathroom') + + # And one part should have no default location at all + W = Part.objects.get(name='Widget') + self.assertIsNone(W.get_default_location()) \ No newline at end of file diff --git a/InvenTree/stock/fixtures/location.yaml b/InvenTree/stock/fixtures/location.yaml new file mode 100644 index 0000000000..f04b192a7d --- /dev/null +++ b/InvenTree/stock/fixtures/location.yaml @@ -0,0 +1,31 @@ +# Create some locations for stock + +- model: stock.stocklocation + pk: 1 + fields: + name: 'Home' + description: 'My house' +- model: stock.stocklocation + pk: 2 + fields: + name: 'Bathroom' + description: 'Where I keep my bath' + parent: 1 +- model: stock.stocklocation + pk: 3 + fields: + name: 'Dining Room' + description: 'A table lives here' + parent: 1 + +- model: stock.stocklocation + pk: 4 + fields: + name: 'Office' + description: 'Place of work' +- model: stock.stocklocation + pk: 5 + fields: + name: 'Drawer' + description: 'In my desk' + parent: 4 \ No newline at end of file From 663cc269b4c3fbd81c13592e60a958adfe7dae31 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 May 2019 23:22:32 +1000 Subject: [PATCH 3/9] Test recursive child count --- InvenTree/part/test_category.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/test_category.py b/InvenTree/part/test_category.py index f2a88c8eb9..ddbcf3babc 100644 --- a/InvenTree/part/test_category.py +++ b/InvenTree/part/test_category.py @@ -85,6 +85,8 @@ class CategoryTest(TestCase): self.assertEqual(self.fasteners.partcount, 2) self.assertEqual(self.capacitors.partcount, 1) + self.assertEqual(self.electronics.partcount, 3) + def test_delete(self): """ Test that category deletion moves the children properly """ @@ -126,4 +128,4 @@ class CategoryTest(TestCase): # And one part should have no default location at all W = Part.objects.get(name='Widget') - self.assertIsNone(W.get_default_location()) \ No newline at end of file + self.assertIsNone(W.get_default_location()) From 3fda5a3925cffef7282aa1d7bbe45cea302731b0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 May 2019 23:30:41 +1000 Subject: [PATCH 4/9] Convert test_part to use fixture data --- InvenTree/part/test_part.py | 41 +++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 93a8652667..75dedf167a 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -2,37 +2,42 @@ from django.test import TestCase import os -from .models import Part, PartCategory +from .models import Part from .models import rename_part_image class SimplePartTest(TestCase): + """ Tests for the Part model """ + + fixtures = [ + 'category', + 'part', + 'location', + ] def setUp(self): + self.R1 = Part.objects.get(name='R_2K2_0805') + self.R2 = Part.objects.get(name='R_4K7_0603') - cat = PartCategory.objects.create(name='TLC', description='Top level category') - - self.px = Part.objects.create(name='x', description='A part called x', buildable=True) - self.py = Part.objects.create(name='y', description='A part called y', consumable=False) - self.pz = Part.objects.create(name='z', description='A part called z', category=cat) + self.C1 = Part.objects.get(name='C_22N_0805') def test_metadata(self): - self.assertEqual(self.px.name, 'x') - self.assertEqual(self.py.get_absolute_url(), '/part/2/') - self.assertEqual(str(self.pz), 'z - A part called z') + self.assertEqual(self.R1.name, 'R_2K2_0805') + self.assertEqual(self.R1.get_absolute_url(), '/part/3/') def test_category(self): - self.assertEqual(self.px.category_path, '') - self.assertEqual(self.pz.category_path, 'TLC') + self.assertEqual(str(self.C1.category), 'Electronics/Capacitors') def test_rename_img(self): - img = rename_part_image(self.px, 'hello.png') - self.assertEqual(img, os.path.join('part_images', 'part_1_img.png')) + img = rename_part_image(self.R1, 'hello.png') + self.assertEqual(img, os.path.join('part_images', 'part_3_img.png')) - img = rename_part_image(self.pz, 'test') - self.assertEqual(img, os.path.join('part_images', 'part_3_img')) + img = rename_part_image(self.R2, 'test') + self.assertEqual(img, os.path.join('part_images', 'part_4_img')) def test_stock(self): - # Stock should initially be zero - self.assertEqual(self.px.total_stock, 0) - self.assertEqual(self.py.available_stock, 0) + # No stock of any resistors + res = Part.objects.filter(description__contains='resistor') + for r in res: + self.assertEqual(r.total_stock, 0) + self.assertEqual(r.available_stock, 0) From 1f80e8c6555c0e4b60502cfbba6b890003674c7e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 May 2019 23:35:52 +1000 Subject: [PATCH 5/9] More tests for Part - barcode - category_path --- InvenTree/part/fixtures/part.yaml | 8 +++++++- InvenTree/part/models.py | 3 +++ InvenTree/part/test_part.py | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/fixtures/part.yaml b/InvenTree/part/fixtures/part.yaml index dc9b17092a..cf8a0141fe 100644 --- a/InvenTree/part/fixtures/part.yaml +++ b/InvenTree/part/fixtures/part.yaml @@ -36,4 +36,10 @@ fields: name: 'Widget' description: 'A watchamacallit' - category: 7 \ No newline at end of file + category: 7 + +- model: part.part + fields: + name: 'Orphan' + description: 'A part without a category' + category: null \ No newline at end of file diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 8bc519d616..7d4173ac55 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -217,6 +217,9 @@ class Part(models.Model): "Part", self.id, reverse('api-part-detail', kwargs={'pk': self.id}), + { + 'name': self.name, + } ) class Meta: diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 75dedf167a..1214f2fc57 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -28,6 +28,10 @@ class SimplePartTest(TestCase): def test_category(self): self.assertEqual(str(self.C1.category), 'Electronics/Capacitors') + orphan = Part.objects.get(name='Orphan') + self.assertIsNone(orphan.category) + self.assertEqual(orphan.category_path, '') + def test_rename_img(self): img = rename_part_image(self.R1, 'hello.png') self.assertEqual(img, os.path.join('part_images', 'part_3_img.png')) @@ -41,3 +45,8 @@ class SimplePartTest(TestCase): for r in res: self.assertEqual(r.total_stock, 0) self.assertEqual(r.available_stock, 0) + + def test_barcode(self): + barcode = self.R1.format_barcode() + self.assertIn('InvenTree', barcode) + self.assertIn(self.R1.name, barcode) From c0e3007e4f18bd1a536c09ea9c132c888e39d6ab Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 May 2019 23:50:24 +1000 Subject: [PATCH 6/9] Add some BomItem tests - Add a bom fixture --- InvenTree/part/fixtures/bom.yaml | 29 ++++++++++++++++++++++++++++ InvenTree/part/fixtures/part.yaml | 14 +++++++++++++- InvenTree/part/test_bom_item.py | 32 ++++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 InvenTree/part/fixtures/bom.yaml diff --git a/InvenTree/part/fixtures/bom.yaml b/InvenTree/part/fixtures/bom.yaml new file mode 100644 index 0000000000..60ca136ce2 --- /dev/null +++ b/InvenTree/part/fixtures/bom.yaml @@ -0,0 +1,29 @@ +# Construct a BOM for item 100 'Bob' + +# 10 x M2x4 LPHS +- model: part.bomitem + fields: + part: 100 + sub_part: 1 + quantity: 10 + +# 40 x R_2K2_0805 +- model: part.bomitem + fields: + part: 100 + sub_part: 3 + quantity: 40 + +# 25 x C_22N_0805 +- model: part.bomitem + fields: + part: 100 + sub_part: 5 + quantity: 25 + +# 3 x Orphan +- model: part.bomitem + fields: + part: 100 + sub_part: 50 + quantity: 3 \ No newline at end of file diff --git a/InvenTree/part/fixtures/part.yaml b/InvenTree/part/fixtures/part.yaml index cf8a0141fe..f9d7c9f4b4 100644 --- a/InvenTree/part/fixtures/part.yaml +++ b/InvenTree/part/fixtures/part.yaml @@ -5,6 +5,7 @@ name: 'M2x4 LPHS' description: 'M2x4 low profile head screw' category: 8 + - model: part.part fields: name: 'M3x12 SHCS' @@ -18,6 +19,7 @@ name: 'R_2K2_0805' description: '2.2kOhm resistor in 0805 package' category: 2 + - model: part.part fields: name: 'R_4K7_0603' @@ -39,7 +41,17 @@ category: 7 - model: part.part + pk: 50 fields: name: 'Orphan' description: 'A part without a category' - category: null \ No newline at end of file + category: null + +# A part that can be made from other parts +- model: part.part + pk: 100 + fields: + name: 'Bob' + description: 'Can we build it?' + buildable: true + \ No newline at end of file diff --git a/InvenTree/part/test_bom_item.py b/InvenTree/part/test_bom_item.py index e3d7aa78ce..f9f73f0fc2 100644 --- a/InvenTree/part/test_bom_item.py +++ b/InvenTree/part/test_bom_item.py @@ -1,7 +1,37 @@ from django.test import TestCase +from .models import Part + class BomItemTest(TestCase): + fixtures = [ + 'category', + 'part', + 'location', + 'bom', + ] + def setUp(self): - pass + self.bob = Part.objects.get(id=100) + self.orphan = Part.objects.get(name='Orphan') + + def test_has_bom(self): + self.assertFalse(self.orphan.has_bom) + self.assertTrue(self.bob.has_bom) + + self.assertEqual(self.bob.bom_count, 4) + + def test_in_bom(self): + parts = self.bob.required_parts() + + self.assertIn(self.orphan, parts) + + def test_bom_export(self): + parts = self.bob.required_parts() + + data = self.bob.export_bom(format='csv') + + for p in parts: + self.assertIn(p.name, data) + self.assertIn(p.description, data) From e2ced187536677e5c94d5e88210f2fafa0a165b1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 5 May 2019 00:00:30 +1000 Subject: [PATCH 7/9] Added some more BomItem tests --- InvenTree/part/models.py | 4 ++-- InvenTree/part/test_bom_item.py | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 7d4173ac55..d406382856 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -477,8 +477,8 @@ class BomItem(models.Model): unique_together = ('part', 'sub_part') def __str__(self): - return "{par} -> {child} ({n})".format( - par=self.part.name, + return "{n} x {child} to make {parent}".format( + parent=self.part.name, child=self.sub_part.name, n=self.quantity) diff --git a/InvenTree/part/test_bom_item.py b/InvenTree/part/test_bom_item.py index f9f73f0fc2..6c1d91810c 100644 --- a/InvenTree/part/test_bom_item.py +++ b/InvenTree/part/test_bom_item.py @@ -1,6 +1,7 @@ from django.test import TestCase +import django.core.exceptions as django_exceptions -from .models import Part +from .models import Part, BomItem class BomItemTest(TestCase): @@ -16,6 +17,10 @@ class BomItemTest(TestCase): self.bob = Part.objects.get(id=100) self.orphan = Part.objects.get(name='Orphan') + def test_str(self): + b = BomItem.objects.get(id=1) + self.assertEqual(str(b), '10 x M2x4 LPHS to make Bob') + def test_has_bom(self): self.assertFalse(self.orphan.has_bom) self.assertTrue(self.bob.has_bom) @@ -35,3 +40,15 @@ class BomItemTest(TestCase): for p in parts: self.assertIn(p.name, data) self.assertIn(p.description, data) + + def test_used_in(self): + self.assertEqual(self.bob.used_in_count, 0) + self.assertEqual(self.orphan.used_in_count, 1) + + def test_self_reference(self): + """ Test that we get an appropriate error when we create a BomItem which points to itself """ + + with self.assertRaises(django_exceptions.ValidationError): + # A validation error should be raised here + item = BomItem.objects.create(part=self.bob, sub_part=self.bob, quantity=7) + item.clean() From fcc83ca7c79afdb8bbb81e903c1af74af6c65e68 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 5 May 2019 00:15:25 +1000 Subject: [PATCH 8/9] Part API test suite now uses test data fixtures --- InvenTree/part/fixtures/category.yaml | 7 +++ InvenTree/part/test_api.py | 87 ++++++++------------------- 2 files changed, 33 insertions(+), 61 deletions(-) diff --git a/InvenTree/part/fixtures/category.yaml b/InvenTree/part/fixtures/category.yaml index 86675a7fa9..2f46dcce65 100644 --- a/InvenTree/part/fixtures/category.yaml +++ b/InvenTree/part/fixtures/category.yaml @@ -7,6 +7,7 @@ description: Electronic components parent: null default_location: 1 # Home + - model: part.partcategory pk: 2 fields: @@ -14,6 +15,7 @@ description: Resistors parent: 1 default_location: null + - model: part.partcategory pk: 3 fields: @@ -21,6 +23,7 @@ description: Capacitors parent: 1 default_location: null + - model: part.partcategory pk: 4 fields: @@ -28,6 +31,7 @@ description: Integrated Circuits parent: 1 default_location: null + - model: part.partcategory pk: 5 fields: @@ -35,6 +39,7 @@ description: Microcontrollers parent: 4 default_location: null + - model: part.partcategory pk: 6 fields: @@ -42,12 +47,14 @@ description: Communication interfaces parent: 4 default_location: null + - model: part.partcategory pk: 7 fields: name: Mechanical description: Mechanical componenets default_location: null + - model: part.partcategory pk: 8 fields: diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 9a0a49447b..b8d9b7ba6d 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -3,9 +3,6 @@ from rest_framework import status from django.urls import reverse from django.contrib.auth import get_user_model -from .models import Part, PartCategory -from .models import BomItem - class PartAPITest(APITestCase): """ @@ -14,36 +11,29 @@ class PartAPITest(APITestCase): - Tests for PartCategory API """ + fixtures = [ + 'category', + 'part', + 'location', + 'bom', + ] + def setUp(self): # Create a user for auth User = get_user_model() User.objects.create_user('testuser', 'test@testing.com', 'password') self.client.login(username='testuser', password='password') - - # Create some test data - TOP = PartCategory.objects.create(name='Top', description='Top level category') - - A = PartCategory.objects.create(name='A', description='Cat A', parent=TOP) - B = PartCategory.objects.create(name='B', description='Cat B', parent=TOP) - C = PartCategory.objects.create(name='C', description='Cat C', parent=TOP) - - Part.objects.create(name='Top.t', description='t in TOP', category=TOP) - - Part.objects.create(name='A.a', description='a in A', category=A) - Part.objects.create(name='B.b', description='b in B', category=B) - Part.objects.create(name='C.c1', description='c1 in C', category=C) - Part.objects.create(name='C.c2', description='c2 in C', category=C) def test_get_categories(self): - # Test that we can retrieve list of part categories + """ Test that we can retrieve list of part categories """ url = reverse('api-part-category-list') response = self.client.get(url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data), 4) + self.assertEqual(len(response.data), 8) def test_add_categories(self): - # Check that we can add categories + """ Check that we can add categories """ data = { 'name': 'Animals', 'description': 'All animals go here' @@ -52,31 +42,32 @@ class PartAPITest(APITestCase): url = reverse('api-part-category-list') response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data['pk'], 5) + + parent = response.data['pk'] # Add some sub-categories to the top-level 'Animals' category for animal in ['cat', 'dog', 'zebra']: data = { 'name': animal, 'description': 'A sort of animal', - 'parent': 5, + 'parent': parent, } response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data['parent'], 5) + self.assertEqual(response.data['parent'], parent) self.assertEqual(response.data['name'], animal) self.assertEqual(response.data['pathstring'], 'Animals/' + animal) # There should be now 8 categories response = self.client.get(url, format='json') - self.assertEqual(len(response.data), 8) + self.assertEqual(len(response.data), 12) def test_cat_detail(self): url = reverse('api-part-category-detail', kwargs={'pk': 4}) response = self.client.get(url, format='json') # Test that we have retrieved the category - self.assertEqual(response.data['description'], 'Cat C') + self.assertEqual(response.data['description'], 'Integrated Circuits') self.assertEqual(response.data['parent'], 1) # Change some data and post it back @@ -87,16 +78,17 @@ class PartAPITest(APITestCase): response = self.client.patch(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['description'], 'Changing the description') + self.assertIsNone(response.data['parent']) def test_get_all_parts(self): url = reverse('api-part-list') response = self.client.get(url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data), 5) + self.assertEqual(len(response.data), 8) def test_get_parts_by_cat(self): url = reverse('api-part-list') - data = {'category': 4} + data = {'category': 2} response = self.client.get(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -104,7 +96,7 @@ class PartAPITest(APITestCase): self.assertEqual(len(response.data), 2) for part in response.data: - self.assertEqual(part['category'], 4) + self.assertEqual(part['category'], 2) def test_include_children(self): """ Test the special 'include_child_categories' flag @@ -116,7 +108,7 @@ class PartAPITest(APITestCase): response = self.client.get(url, data, format='json') # There should be 1 part in this category - self.assertEqual(len(response.data), 1) + self.assertEqual(len(response.data), 0) data['include_child_categories'] = 1 @@ -125,35 +117,10 @@ class PartAPITest(APITestCase): # Now there should be 5 total parts self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data), 5) - - -class BomAPITest(APITestCase): - - def setUp(self): - # Create a user for auth - User = get_user_model() - User.objects.create_user('testuser', 'test@testing.com', 'password') - - self.client.login(username='testuser', password='password') - - # Create some parts - m1 = Part.objects.create(name='A thing', description='Made from other parts', buildable=True) - m2 = Part.objects.create(name='Another thing', description='Made from other parts', buildable=True) - - s1 = Part.objects.create(name='Sub 1', description='Required to make a thing') - s2 = Part.objects.create(name='Sub 2', description='Required to make a thing') - s3 = Part.objects.create(name='Sub 3', description='Required to make a thing') - - # Link BOM items together - BomItem.objects.create(part=m1, sub_part=s1, quantity=10) - BomItem.objects.create(part=m1, sub_part=s2, quantity=100) - BomItem.objects.create(part=m1, sub_part=s3, quantity=40) - - BomItem.objects.create(part=m2, sub_part=s3, quantity=7) + self.assertEqual(len(response.data), 3) def test_get_bom_list(self): - # There should be 4 BomItem objects in the database + """ There should be 4 BomItem objects in the database """ url = reverse('api-bom-list') response = self.client.get(url, format='json') self.assertEqual(len(response.data), 4) @@ -163,7 +130,7 @@ class BomAPITest(APITestCase): url = reverse('api-bom-detail', kwargs={'pk': 3}) response = self.client.get(url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['quantity'], 40) + self.assertEqual(response.data['quantity'], 25) # Increase the quantity data = response.data @@ -181,7 +148,7 @@ class BomAPITest(APITestCase): url = reverse('api-bom-list') data = { - 'part': 2, + 'part': 100, 'sub_part': 4, 'quantity': 777, } @@ -194,9 +161,7 @@ class BomAPITest(APITestCase): response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - # Now try to create a BomItem which references itself + # TODO - Now try to create a BomItem which references itself data['part'] = 2 data['sub_part'] = 2 response = self.client.post(url, data, format='json') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('cannot be added to its own', str(response.data['sub_part'][0])) From 22afccd29426886f8fc2f85b125444cee73c84ca Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 5 May 2019 00:21:54 +1000 Subject: [PATCH 9/9] Add tests for the custom templates --- InvenTree/part/test_part.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 1214f2fc57..486d7c5684 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -4,9 +4,27 @@ import os from .models import Part from .models import rename_part_image +from .templatetags import inventree_extras -class SimplePartTest(TestCase): +class TemplateTagTest(TestCase): + """ Tests for the custom template tag code """ + + def test_multiply(self): + self.assertEqual(inventree_extras.multiply(3, 5), 15) + + def test_version(self): + self.assertEqual(type(inventree_extras.inventree_version()), str) + + def test_hash(self): + hash = inventree_extras.inventree_commit() + self.assertEqual(len(hash), 7) + + def test_github(self): + self.assertIn('github.com', inventree_extras.inventree_github()) + + +class PartTest(TestCase): """ Tests for the Part model """ fixtures = [