2015-06-11 27 views
7

Tôi đang gặp sự cố về cơ sở dữ liệu trong các thử nghiệm đơn vị của mình. Tôi nghĩ rằng nó có một cái gì đó để làm với cách tôi đang sử dụng TestCase và setUpData.Thử nghiệm Django: setUpTestData trên Postgres ném: "Giá trị khóa trùng lặp vi phạm ràng buộc duy nhất"

Khi tôi cố gắng thiết lập dữ liệu thử nghiệm của tôi với các giá trị nhất định, các cuộc thử nghiệm ném các lỗi sau:

django.db.utils.IntegrityError: duplicate key value violates unique constraint 

... 

psycopg2.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_productgroup_product_name_48ec6f8d_uniq" 
DETAIL: Key (product_name)=(Almonds) already exists. 

tôi đã thay đổi tất cả các từ khóa chính của tôi và nó dường như được chạy tốt. Nó dường như không ảnh hưởng đến bất kỳ thử nghiệm nào.

Tuy nhiên, tôi lo ngại rằng tôi đang làm điều gì đó sai. Khi nó lần đầu tiên xảy ra, tôi đảo ngược về giá trị của một giờ làm việc trên ứng dụng của tôi (không phải là nhiều mã cho một noob), mà sửa chữa vấn đề.

Sau đó, khi tôi đã viết các thay đổi trở lại, cùng một vấn đề được trình bày lại. TestCase được dán dưới đây. Vấn đề này dường như xảy ra sau khi tôi thêm các mục sắp xếp, nhưng tương ứng với các mục ở trên nó.

Tôi không muốn tiếp tục và thay đổi khóa và url chính trong các bài kiểm tra của mình, vì vậy nếu có ai thấy điều gì đó sai với cách tôi đang sử dụng, hãy giúp tôi. Cảm ơn!

TestCase

class DetailsPageTest(TestCase): 


@classmethod 
def setUpTestData(cls): 

    cls.product1 = ProductGroup.objects.create(
         product_name="Almonds" 
         ) 
    cls.variety1 = Variety.objects.create(
         product_group = cls.product1, 
         variety_name = "non pareil", 
         husked = False, 
         finished = False, 
         ) 

    cls.supplier1 = Supplier.objects.create(
         company_name = "Acme", 
         company_location = "Acme Acres", 
         contact_info = "Call me!" 
         ) 

    cls.shipment1 = Purchase.objects.create(
         tag=9, 
         shipment_id=9999, 
         supplier_id = cls.supplier1, 
         purchase_date='2015-01-09', 
         purchase_price=9.99, 
         product_name=cls.variety1, 
         pieces=99, 
         kgs=999, 
         crackout_estimate=99.9 
         ) 
    cls.shipment2 = Purchase.objects.create(
         tag=8, 
         shipment_id=8888, 
         supplier_id=cls.supplier1, 
         purchase_date='2015-01-08', 
         purchase_price=8.88, 
         product_name=cls.variety1, 
         pieces=88, 
         kgs=888, 
         crackout_estimate=88.8 
         ) 
    cls.shipment3 = Purchase.objects.create(
         tag=7, 
         shipment_id=7777, 
         supplier_id=cls.supplier1, 
         purchase_date='2014-01-07', 
         purchase_price=7.77, 
         product_name=cls.variety1, 
         pieces=77, 
         kgs=777, 
         crackout_estimate=77.7 
         ) 

    cls.sortrecord1 = SortingRecords.objects.create(
         tag=cls.shipment1, 
         date="2015-02-05", 
         bags_sorted=20, 
         turnout=199, 
         ) 

    cls.sortrecord2 = SortingRecords.objects.create(
         tag=cls.shipment1, 
         date="2015-02-07", 
         bags_sorted=40, 
         turnout=399, 
         ) 
    cls.sortrecord3 = SortingRecords.objects.create(
         tag=cls.shipment1, 
         date='2015-02-09', 
         bags_sorted=30, 
         turnout=299, 
         ) 

Models

from datetime import datetime 

from django.db import models 
from django.db.models import Q 


class ProductGroup(models.Model): 
    product_name = models.CharField(max_length=140, primary_key=True) 

    def __str__(self): 
     return self.product_name 

    class Meta: 
     verbose_name = "Product" 

class Supplier(models.Model): 
    company_name = models.CharField(max_length=45) 
    company_location = models.CharField(max_length=45) 
    contact_info = models.CharField(max_length=256) 

    class Meta: 
     ordering = ["company_name"] 

    def __str__(self): 
     return self.company_name 

class Variety(models.Model): 
    product_group = models.ForeignKey(ProductGroup) 
    variety_name = models.CharField(max_length=140) 
    husked = models.BooleanField() 
    finished = models.BooleanField() 
    description = models.CharField(max_length=500, blank=True) 

    class Meta: 
     ordering = ["product_group_id"] 
     verbose_name_plural = "Varieties" 

    def __str__(self): 
     return self.variety_name 


class PurchaseYears(models.Manager): 

    def purchase_years_list(self): 
     unique_years = Purchase.objects.dates('purchase_date', 'year') 
     results_list = [] 
     for p in unique_years: 
      results_list.append(p.year) 
     return results_list 


class Purchase(models.Model): 
    tag = models.IntegerField(primary_key=True) 
    product_name = models.ForeignKey(Variety, related_name='purchases') 
    shipment_id = models.CharField(max_length=24) 
    supplier_id = models.ForeignKey(Supplier) 
    purchase_date = models.DateField() 
    estimated_delivery = models.DateField(null=True, blank=True) 
    purchase_price = models.DecimalField(max_digits=6, decimal_places=3) 
    pieces = models.IntegerField() 
    kgs = models.IntegerField() 
    crackout_estimate = models.DecimalField(max_digits=6,decimal_places=3, null=True) 
    crackout_actual = models.DecimalField(max_digits=6,decimal_places=3, null=True) 
    objects = models.Manager() 
    purchase_years = PurchaseYears() 
    # Keep manager as "objects" in case admin, etc. needs it. Filter can be called like so: 
    # Purchase.objects.purchase_years_list() 
    # Managers in docs: https://docs.djangoproject.com/en/1.8/intro/tutorial01/ 

    class Meta: 
     ordering = ["purchase_date"] 

    def __str__(self): 
     return self.shipment_id 

    def _weight_conversion(self): 
     return round(self.kgs * 2.20462) 
    lbs = property(_weight_conversion) 

class SortingModelsBagsCalulator(models.Manager): 

    def total_sorted(self, record_date, current_set): 
     sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if 
        SortingRecords['date'] <= record_date] 
     return sum(sorted) 


class SortingRecords(models.Model): 
    tag = models.ForeignKey(Purchase, related_name='sorting_record') 
    date = models.DateField() 
    bags_sorted = models.IntegerField() 
    turnout = models.IntegerField() 
    objects = models.Manager() 

    def __str__(self): 
     return "%s [%s]" % (self.date, self.tag.tag) 

    class Meta: 
     ordering = ["date"] 
     verbose_name_plural = "Sorting Records" 

    def _calculate_kgs_sorted(self): 
     kg_per_bag = self.tag.kgs/self.tag.pieces 
     kgs_sorted = kg_per_bag * self.bags_sorted 
     return (round(kgs_sorted, 2)) 
    kgs_sorted = property(_calculate_kgs_sorted) 

    def _byproduct(self): 
     waste = self.kgs_sorted - self.turnout 
     return (round(waste, 2)) 
    byproduct = property(_byproduct) 

    def _bags_remaining(self): 
     current_set = SortingRecords.objects.values().filter(~Q(id=self.id), tag=self.tag) 
     sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if 
        SortingRecords['date'] <= self.date] 
     remaining = self.tag.pieces - sum(sorted) - self.bags_sorted 
     return remaining 
    bags_remaining = property(_bags_remaining) 

EDIT

Nó cũng không thành công với số nguyên, như vậy.

django.db.utils.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_purchase_pkey" 
DETAIL: Key (tag)=(9) already exists. 

UDPATE

Vì vậy, tôi nên đã đề cập trước đó này, nhưng tôi hoàn toàn quên. Tôi có hai tệp thử nghiệm đơn vị sử dụng cùng một dữ liệu. Chỉ cần cho đá, tôi phù hợp với một khóa chính trong cả hai trường hợp của setUpTestData() đến một giá trị khác nhau và chắc chắn đủ, tôi đã nhận lỗi tương tự.

Hai thiết lập này hoạt động tốt song song trước khi tôi thêm nhiều dữ liệu hơn vào một trong số chúng. Bây giờ, có vẻ như họ cần các giá trị khác nhau. Tôi đoán bạn chỉ có thể lấy đi bằng cách sử dụng dữ liệu lặp lại quá lâu.

+1

tại sao bạn không để cho các db chọn id? –

+0

bạn nên đặt các mô hình trong bài đăng của mình. Có thể 'SortingRecords.tag' phải là duy nhất không? –

+0

Hah. Điều đó có lẽ sẽ là khôn ngoan. Tôi nghĩ rằng tôi thiết lập nó theo cách này ban đầu bởi vì tôi muốn ngăn chặn sự xuất hiện của nhiều thẻ, sản phẩm, vv .. Đó là cách rõ ràng nhất vào thời điểm đó, nhưng tôi chắc chắn có một cách thông minh hơn để làm điều đó. –

Trả lời

0

tôi phát hiện ra vấn đề này, như đã nêu ở dưới cùng của câu hỏi.

Từ những gì tôi có thể biết, cơ sở dữ liệu không thích tôi bằng cách sử dụng dữ liệu trùng lặp trong các phương pháp setUpTestData() của hai thử nghiệm khác nhau. Thay đổi các giá trị khóa chính trong bài kiểm tra thứ hai đã khắc phục sự cố.

0

Nhật ký bạn đã cung cấp tiểu bang DETAIL: Key (product_name)=(Almonds) already exists. Bạn đã xác minh trong db của mình chưa?

Để ngăn chặn các lỗi như vậy trong tương lai, bạn nên thêm tiền tố tất cả các bạn chuỗi dữ liệu thử nghiệm bởi test_

+0

Thực ra, Almonds tồn tại như một tên sản phẩm và có một thời gian. Tuy nhiên, đây chưa bao giờ là vấn đề trước đó. Các thử nghiệm luôn có thể chạy thành công dưới TestCase. Ngoài ra, nó mang lại cho tôi cùng một lỗi cho các thẻ, mà không được nhân đôi trong cơ sở dữ liệu, nhưng (được cho là) ​​được tạo ra với mỗi bài kiểm tra, sau đó loại bỏ. Tôi nên lặp lại, dữ liệu bí ẩn này không thực sự xuất hiện trong các thử nghiệm. –

+0

Gần đây bạn có sử dụng 'manage.py migrate' không? Tôi nghĩ rằng nó tạo ra một bản chụp của db được sử dụng như một điểm khởi đầu bởi các bài kiểm tra –

+0

Vâng, tôi đã thực sự làm hỏng các di chuyển khá xấu, đó là lý do tại sao tôi đảo ngược một loạt các công việc. Rõ ràng nỗ lực đó đã không khắc phục được vấn đề. Dù sao, tôi đã cố gắng để tạo lại một lỗi cho bạn, nhưng vấn đề dường như đã biến mất. Tôi không có đủ đại diện để upvote, nhưng cảm ơn sự giúp đỡ của bạn. –

0

Tôi nghĩ rằng vấn đề ở đây là bạn đã có một phương pháp tearDownClass trong TestCase của bạn mà không có cuộc gọi đến phương thức siêu. Bằng cách này, django TestCase mất các chức năng giao dịch phía sau setUpTestData để nó không làm sạch db thử nghiệm của bạn sau khi một TestCase kết thúc.

Kiểm tra cảnh báo trong django tài liệu ở đây: https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.SimpleTestCase.allow_database_queries

Các vấn đề liên quan