diff --git a/.coveragerc b/.coveragerc
index ed8dd1d86e..e953c6c86c 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -2,4 +2,8 @@
 source = ./InvenTree
 omit =
     # Do not run coverage on migration files
-    */migrations/*
\ No newline at end of file
+    */migrations/*
+    InvenTree/manage.py
+    Inventree/InvenTree/middleware.py
+    Inventree/InvenTree/utils.py
+    Inventree/InvenTree/wsgi.py
\ No newline at end of file
diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py
index 925d9eb104..e5f5d99869 100644
--- a/InvenTree/company/tests.py
+++ b/InvenTree/company/tests.py
@@ -1,6 +1,9 @@
 from django.test import TestCase
 
-from .models import Company
+import os
+
+from .models import Company, Contact
+from .models import rename_company_image
 
 
 class CompanySimpleTest(TestCase):
@@ -16,4 +19,43 @@ class CompanySimpleTest(TestCase):
     def test_company_model(self):
         c = Company.objects.get(pk=1)
         self.assertEqual(c.name, 'ABC Co.')
+        self.assertEqual(str(c), 'ABC Co. - Seller of ABC products')
+
+    def test_company_url(self):
+        c = Company.objects.get(pk=1)
         self.assertEqual(c.get_absolute_url(), '/company/1/')
+
+    def test_image_renamer(self):
+        c = Company.objects.get(pk=1)
+        rn = rename_company_image(c, 'test.png')
+        self.assertEqual(rn, 'company_images' + os.path.sep + 'company_1_img.png')
+
+        rn = rename_company_image(c, 'test2')
+        self.assertEqual(rn, 'company_images' + os.path.sep + 'company_1_img')
+
+    def test_part_count(self):
+        # Initially the company should have no associated parts
+        c = Company.objects.get(pk=1)
+        self.assertEqual(c.has_parts, False)
+
+        # TODO - Add some supplier parts here
+
+
+class ContactSimpleTest(TestCase):
+
+    def setUp(self):
+        # Create a simple company
+        c = Company.objects.create(name='Test Corp.', description='We make stuff good')
+
+        # Add some contacts
+        Contact.objects.create(name='Joe Smith', company=c)
+        Contact.objects.create(name='Fred Smith', company=c)
+        Contact.objects.create(name='Sally Smith', company=c)
+
+    def test_exists(self):
+        self.assertEqual(Contact.objects.count(), 3)
+
+    def test_delete(self):
+        # Remove the parent company
+        Company.objects.get(pk=1).delete()
+        self.assertEqual(Contact.objects.count(), 0)
diff --git a/InvenTree/part/test_category.py b/InvenTree/part/test_category.py
index 9fee29332c..3b732f80e8 100644
--- a/InvenTree/part/test_category.py
+++ b/InvenTree/part/test_category.py
@@ -42,7 +42,7 @@ class CategoryTest(TestCase):
         childs = self.p1.getUniqueChildren()
 
         self.assertIn(self.p2.id, childs)
-        self.assertIn(self.p2.id, childs)
+        self.assertIn(self.p3.id, childs)
 
     def test_unique_parents(self):
         parents = self.p2.getUniqueParents()
@@ -64,3 +64,13 @@ class CategoryTest(TestCase):
         self.assertEqual(self.p1.partcount, 3)
         self.assertEqual(self.p2.partcount, 3)
         self.assertEqual(self.p3.partcount, 1)
+
+    def test_delete(self):
+        self.assertEqual(Part.objects.filter(category=self.p1).count(), 0)
+
+        # Delete p2 (it has 2 direct parts and one child category)
+        self.p2.delete()
+
+        self.assertEqual(Part.objects.filter(category=self.p1).count(), 2)
+
+        self.assertEqual(PartCategory.objects.get(pk=self.p3.id).parent, self.p1)
diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py
index c9ed2fd7b3..93a8652667 100644
--- a/InvenTree/part/test_part.py
+++ b/InvenTree/part/test_part.py
@@ -1,6 +1,9 @@
 from django.test import TestCase
 
+import os
+
 from .models import Part, PartCategory
+from .models import rename_part_image
 
 
 class SimplePartTest(TestCase):
@@ -21,3 +24,15 @@ class SimplePartTest(TestCase):
     def test_category(self):
         self.assertEqual(self.px.category_path, '')
         self.assertEqual(self.pz.category_path, 'TLC')
+
+    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.pz, 'test')
+        self.assertEqual(img, os.path.join('part_images', 'part_3_img'))
+
+    def test_stock(self):
+        # Stock should initially be zero
+        self.assertEqual(self.px.total_stock, 0)
+        self.assertEqual(self.py.available_stock, 0)
diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py
index 312bff9bbe..7333cc4f7f 100644
--- a/InvenTree/stock/models.py
+++ b/InvenTree/stock/models.py
@@ -28,11 +28,6 @@ class StockLocation(InvenTreeTree):
     def get_absolute_url(self):
         return reverse('stock-location-detail', kwargs={'pk': self.id})
 
-    @property
-    def stock_items(self):
-        return self.stockitem_set.all()
-
-    @property
     def has_items(self):
         return self.stock_items.count() > 0
 
@@ -128,7 +123,7 @@ class StockItem(models.Model):
 
     # Where the part is stored. If the part has been used to build another stock item, the location may not make sense
     location = models.ForeignKey(StockLocation, on_delete=models.DO_NOTHING,
-                                 related_name='items', blank=True, null=True,
+                                 related_name='stock_items', blank=True, null=True,
                                  help_text='Where is this stock item located?')
 
     # If this StockItem belongs to another StockItem (e.g. as part of a sub-assembly)
@@ -253,7 +248,7 @@ class StockItem(models.Model):
         count = int(count)
 
         if count < 0 or self.infinite:
-            return
+            return False
 
         self.quantity = count
         self.stocktake_date = datetime.now().date()
@@ -265,6 +260,8 @@ class StockItem(models.Model):
                                   notes=notes,
                                   system=True)
 
+        return True
+
     @transaction.atomic
     def add_stock(self, quantity, user, notes=''):
         """ Add items to stock
@@ -276,7 +273,7 @@ class StockItem(models.Model):
 
         # Ignore amounts that do not make sense
         if quantity <= 0 or self.infinite:
-            return
+            return False
 
         self.quantity += quantity
 
@@ -287,18 +284,20 @@ class StockItem(models.Model):
                                   notes=notes,
                                   system=True)
 
+        return True
+
     @transaction.atomic
     def take_stock(self, quantity, user, notes=''):
         """ Remove items from stock
         """
 
         if self.quantity == 0:
-            return
+            return False
 
         quantity = int(quantity)
 
         if quantity <= 0 or self.infinite:
-            return
+            return False
 
         self.quantity -= quantity
 
@@ -312,6 +311,8 @@ class StockItem(models.Model):
                                   notes=notes,
                                   system=True)
 
+        return True
+
     def __str__(self):
         s = '{n} x {part}'.format(
             n=self.quantity,
@@ -322,10 +323,6 @@ class StockItem(models.Model):
 
         return s
 
-    @property
-    def is_trackable(self):
-        return self.part.trackable
-
 
 class StockItemTracking(models.Model):
     """ Stock tracking entry
diff --git a/InvenTree/stock/test_stock_item.py b/InvenTree/stock/test_stock_item.py
deleted file mode 100644
index becd6e4e69..0000000000
--- a/InvenTree/stock/test_stock_item.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.test import TestCase
-
-
-class StockItemTest(TestCase):
-
-    def setUp(self):
-        pass
diff --git a/InvenTree/stock/test_stock_location.py b/InvenTree/stock/test_stock_location.py
deleted file mode 100644
index 0a89aeed33..0000000000
--- a/InvenTree/stock/test_stock_location.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.test import TestCase
-
-
-class StockLocationTest(TestCase):
-
-    def setUp(self):
-        pass
diff --git a/InvenTree/stock/test_stock_tracking.py b/InvenTree/stock/test_stock_tracking.py
deleted file mode 100644
index 15b79cbe66..0000000000
--- a/InvenTree/stock/test_stock_tracking.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.test import TestCase
-
-
-class StockTrackingTest(TestCase):
-
-    def setUp(self):
-        pass
diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py
new file mode 100644
index 0000000000..d5b1f8c3f1
--- /dev/null
+++ b/InvenTree/stock/tests.py
@@ -0,0 +1,162 @@
+from django.test import TestCase
+
+from .models import StockLocation, StockItem, StockItemTracking
+from part.models import Part
+
+
+class StockTest(TestCase):
+    """
+    Tests to ensure that the stock location tree functions correcly
+    """
+
+    def setUp(self):
+        # Initialize some categories
+        self.loc1 = StockLocation.objects.create(name='L0',
+                                                 description='Top level category',
+                                                 parent=None)
+
+        self.loc2 = StockLocation.objects.create(name='L1.1',
+                                                 description='Second level 1/2',
+                                                 parent=self.loc1)
+
+        self.loc3 = StockLocation.objects.create(name='L1.2',
+                                                 description='Second level 2/2',
+                                                 parent=self.loc1)
+
+        self.loc4 = StockLocation.objects.create(name='L2.1',
+                                                 description='Third level 1/2',
+                                                 parent=self.loc2)
+
+        self.loc5 = StockLocation.objects.create(name='L2.2',
+                                                 description='Third level 2/2',
+                                                 parent=self.loc3)
+
+        # Add some items to loc4 (all copies of a single part)
+        p = Part.objects.create(name='ACME Part', description='This is a part!')
+
+        StockItem.objects.create(part=p, location=self.loc4, quantity=1000)
+        StockItem.objects.create(part=p, location=self.loc4, quantity=250)
+        StockItem.objects.create(part=p, location=self.loc4, quantity=12)
+
+    def test_simple(self):
+        it = StockItem.objects.get(pk=2)
+        self.assertEqual(it.get_absolute_url(), '/stock/item/2/')
+        self.assertEqual(self.loc4.get_absolute_url(), '/stock/location/4/')
+
+    def test_strings(self):
+        it = StockItem.objects.get(pk=2)
+        self.assertEqual(str(it), '250 x ACME Part @ L2.1')
+
+    def test_parent(self):
+        self.assertEqual(StockLocation.objects.count(), 5)
+        self.assertEqual(self.loc1.parent, None)
+        self.assertEqual(self.loc2.parent, self.loc1)
+        self.assertEqual(self.loc5.parent, self.loc3)
+
+    def test_children(self):
+        self.assertTrue(self.loc1.has_children)
+        self.assertFalse(self.loc5.has_children)
+
+        childs = self.loc1.getUniqueChildren()
+
+        self.assertIn(self.loc2.id, childs)
+        self.assertIn(self.loc4.id, childs)
+
+    def test_paths(self):
+        self.assertEqual(self.loc5.pathstring, 'L0/L1.2/L2.2')
+
+    def test_items(self):
+        # Location 5 should have no items
+        self.assertFalse(self.loc5.has_items())
+        self.assertFalse(self.loc3.has_items())
+
+        # Location 4 should have three stock items
+        self.assertEqual(self.loc4.stock_items.count(), 3)
+
+    def test_stock_count(self):
+        part = Part.objects.get(pk=1)
+
+        # There should be 1262 items in stock
+        self.assertEqual(part.total_stock, 1262)
+
+    def test_delete_location(self):
+        # Delete location - parts should move to parent location
+        self.loc4.delete()
+
+        # There should still be 3 stock items
+        self.assertEqual(StockItem.objects.count(), 3)
+
+        # Parent location should have moved up to loc2
+        for it in StockItem.objects.all():
+            self.assertEqual(it.location, self.loc2)
+
+    def test_move(self):
+        # Move the first stock item to loc5
+        it = StockItem.objects.get(pk=1)
+        self.assertNotEqual(it.location, self.loc5)
+        self.assertTrue(it.move(self.loc5, 'Moved to another place', None))
+        self.assertEqual(it.location, self.loc5)
+
+        # Check that a tracking item was added
+        track = StockItemTracking.objects.filter(item=it).latest('id')
+
+        self.assertEqual(track.item, it)
+        self.assertIn('Moved to', track.title)
+        self.assertEqual(track.notes, 'Moved to another place')
+
+    def test_self_move(self):
+        # Try to move an item to its current location (should fail)
+        it = StockItem.objects.get(pk=1)
+
+        n = it.tracking_info.count()
+        self.assertFalse(it.move(it.location, 'Moved to same place', None))
+
+        # Ensure tracking info was not added
+        self.assertEqual(it.tracking_info.count(), n)
+
+    def test_stocktake(self):
+        # Perform stocktake
+        it = StockItem.objects.get(pk=2)
+        self.assertEqual(it.quantity, 250)
+        it.stocktake(255, None, notes='Counted items!')
+
+        self.assertEqual(it.quantity, 255)
+
+        # Check that a tracking item was added
+        track = StockItemTracking.objects.filter(item=it).latest('id')
+
+        self.assertIn('Stocktake', track.title)
+        self.assertIn('Counted items', track.notes)
+
+        n = it.tracking_info.count()
+        self.assertFalse(it.stocktake(-1, None, 'test negative stocktake'))
+
+        # Ensure tracking info was not added
+        self.assertEqual(it.tracking_info.count(), n)
+
+    def test_add_stock(self):
+        it = StockItem.objects.get(pk=2)
+        n = it.quantity
+        it.add_stock(45, None, notes='Added some items')
+
+        self.assertEqual(it.quantity, n + 45)
+
+        # Check that a tracking item was added
+        track = StockItemTracking.objects.filter(item=it).latest('id')
+
+        self.assertIn('Added', track.title)
+        self.assertIn('Added some items', track.notes)
+
+    def test_take_stock(self):
+        it = StockItem.objects.get(pk=2)
+        n = it.quantity
+        it.take_stock(15, None, notes='Removed some items')
+
+        self.assertEqual(it.quantity, n - 15)
+
+        # Check that a tracking item was added
+        track = StockItemTracking.objects.filter(item=it).latest('id')
+
+        self.assertIn('Removed', track.title)
+        self.assertIn('Removed some items', track.notes)
+        self.assertTrue(it.has_tracking_info)
diff --git a/Makefile b/Makefile
index 8db2a2110c..dadbb44999 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ style:
 
 test:
 	python InvenTree/manage.py check
-	python manage.py test build company part stock
+	python InvenTree/manage.py test build company part stock
 
 migrate:
 	python InvenTree/manage.py makemigrations company