2010-02-15 35 views
22

Tôi đang cố gắng xây dựng các thử nghiệm cho một số mô hình có một FileField. Mô hình này trông như thế này:Kiểm tra Django FileField sử dụng đồ đạc thử nghiệm

class SolutionFile(models.Model): 
    ''' 
    A file from a solution. 
    ''' 
    solution = models.ForeignKey(Solution) 
    file = models.FileField(upload_to=make_solution_file_path) 

tôi đã gặp phải hai vấn đề:

  1. Khi lưu dữ liệu vào một vật cố sử dụng ./manage.py dumpdata, nội dung tập tin sẽ không được lưu, chỉ có tên tập tin được lưu vào vật cố định. Trong khi tôi thấy điều này là hành vi mong đợi vì nội dung tệp không được lưu vào cơ sở dữ liệu, tôi muốn bằng cách nào đó bao gồm thông tin này trong lịch thi đấu để kiểm tra.

  2. Tôi có một trường hợp thử nghiệm để tải lên một tập tin đó trông như thế này:

    def test_post_solution_file(self): 
        import tempfile 
        import os 
        filename = tempfile.mkstemp()[1] 
        f = open(filename, 'w') 
        f.write('These are the file contents') 
        f.close() 
        f = open(filename, 'r') 
        post_data = {'file': f} 
        response = self.client.post(self.solution.get_absolute_url()+'add_solution_file/', post_data, 
               follow=True) 
        f.close() 
        os.remove(filename) 
        self.assertTemplateUsed(response, 'tests/solution_detail.html') 
        self.assertContains(response, os.path.basename(filename)) 
    

Trong khi thử nghiệm này chỉ hoạt động tốt, nó để lại các tập tin được tải lên trong thư mục phương tiện truyền thông sau khi kết thúc. Tất nhiên, việc xóa có thể được thực hiện trong tearDown(), nhưng tôi đã tự hỏi nếu Django đã có một cách khác để đối phó với điều này.

Một giải pháp mà tôi đã nghĩ đến là sử dụng một thư mục phương tiện khác để kiểm tra phải được đồng bộ hóa với các thiết bị thử nghiệm. Có cách nào để chỉ định thư mục phương tiện khác trong settings.py khi thử nghiệm đang được chạy không? Và tôi có thể bao gồm một số loại móc để dumpdata để nó đồng bộ các tập tin trong các thư mục phương tiện truyền thông?

Vì vậy, có cách nào khác về Pythonic hoặc Django cụ thể để xử lý các bài kiểm tra đơn vị liên quan đến tệp không?

+0

Vì vậy os.remove (foo) làm việc does't? Nó có ném một ngoại lệ không? Có lẽ không có những người bảo mật chính xác trên thư mục/tệp đó để có thể xóa nó khỏi bên trong bài kiểm tra đơn vị của bạn? –

+0

'os.remove() 'một phần trong đoạn mã sẽ xóa tệp khỏi thư mục tạm thời. Để xóa tệp đã tải lên, tôi phải tìm trong thư mục phương tiện và theo một logic phức tạp hơn để tìm vị trí chính xác của tệp. Tôi đang tìm một cách tự động, dễ dàng hơn để làm điều đó, nếu nó còn tồn tại. – sttwister

+1

D'oh, xin lỗi! Tôi đã đọc sai bài đăng của bạn. Cài đặt hacking.MEDIA_ROOT = '/ path/to/project/static/và/then/alternative/storage /' và settings.MEDIA_URL = '/ static/và/then/alternative/storage /' trong thiết lập của bạn cho các bài kiểm tra của bạn ? Hacky, nhưng có thể thực hiện công việc ... –

Trả lời

17

Django cung cấp một cách tuyệt vời để viết bài kiểm tra trên FileFields mà không mucking về trong hệ thống tập tin thực - sử dụng một SimpleUploadedFile.

from django.core.files.uploadedfile import SimpleUploadedFile 

my_model.file_field = SimpleUploadedFile('best_file_eva.txt', 'these are the file contents!') 

Đây là một trong những tính năng huyền diệu của django-that-don't-show-up-in-the-docs :). Tuy nhiên nó được gọi là here.

+3

Nội dung không nhị phân tăng lỗi trong Python 3+; bạn có thể sửa lỗi đó bằng cách đơn giản tạo nội dung nhị phân, như sau: 'my_model.file_field = SimpleUploadedFile ('best_file_eva.txt', b'these là nội dung tập tin! ')' – LaundroMat

3

Tôi đã viết các bài kiểm tra đơn vị cho toàn bộ ứng dụng thư viện trước đây và những gì đã hoạt động tốt cho tôi là sử dụng tempfile và mô-đun ngắt để tạo bản sao của tệp thử nghiệm trong các thư mục tạm thời và sau đó xóa chúng.

Ví dụ sau đây là không làm việc/hoàn thành, nhưng sẽ giúp bạn trên con đường đúng đắn:

import os, shutil, tempfile 

PATH_TEMP = tempfile.mkdtemp(dir=os.path.join(MY_PATH, 'temp')) 

def make_objects(): 
    filenames = os.listdir(TEST_FILES_DIR) 

    if not os.access(PATH_TEMP, os.F_OK): 
     os.makedirs(PATH_TEMP) 

    for filename in filenames: 
     name, extension = os.path.splitext(filename) 
     new = os.path.join(PATH_TEMP, filename) 
     shutil.copyfile(os.path.join(TEST_FILES_DIR, filename), new) 

     #Do something with the files/FileField here 

def remove_objects(): 
    shutil.rmtree(PATH_TEMP) 

tôi chạy các phương pháp đó trong thiết lập() và teardown() phương pháp kiểm tra đơn vị của tôi và nó hoạt động tuyệt quá! Bạn đã có một bản sao sạch các tệp của mình để kiểm tra trường tệp của bạn có thể sử dụng lại và có thể dự đoán được.

+0

Tôi không thấy làm thế nào mà có thể giúp tôi. Tôi muốn ghi đè lên thư mục phương tiện truyền thông của Django với một bài kiểm tra. Và tôi cũng muốn bằng cách nào đó xuất/sao chép các tệp khi sử dụng './manage.py dumpdata'. – sttwister

+0

Ghi đè thư mục phương tiện của django là một ý tưởng tồi. Trừ khi bạn di chuyển thư mục phương tiện hiện tại ở một nơi khác và đặt nó trở lại sau đó bạn sẽ không bao giờ có thể chạy thử nghiệm trên trang web trực tiếp của bạn bởi vì nó sẽ là một hoạt động phá hoại. Bạn * có thể * di chuyển thư mục phương tiện và đặt nó trở lại bằng cách sử dụng các máy đóng như tôi đã đề xuất ở trên. Ngoài ra, dumpdata sẽ không bao giờ xuất các tệp cho bạn. Bạn sẽ phải viết kịch bản của riêng bạn hoặc manage.py phần mở rộng cho điều đó. –

0

Đây là những gì tôi đã làm cho thử nghiệm của mình. Sau khi tải các tập tin cần kết thúc trong bất động sản ảnh của đối tượng mô hình tổ chức của tôi:

import tempfile 
    filename = tempfile.mkstemp()[1] 
    f = open(filename, 'w') 
    f.write('These are the file contents') 
    f.close() 
    f = open(filename, 'r') 
    post_data = {'file': f} 
    response = self.client.post("/org/%d/photo" % new_org_data["id"], post_data) 
    f.close() 
    self.assertEqual(response.status_code, 200) 

    ## Check the file 
    ## org is where the file should end up 
    org = models.Organization.objects.get(pk=new_org_data["id"]) 
    self.assertEqual("These are the file contents", org.photo.file.read()) 

    ## Remove the file 
    import os 
    os.remove(org.photo.path) 
5

Bạn có thể ghi đè lên các thiết lập MEDIA_ROOT cho các bài kiểm tra của bạn bằng cách sử dụng @override_settings() trang trí as documented:

from django.test import override_settings 


@override_settings(MEDIA_ROOT='/tmp/django_test') 
def test_post_solution_file(self): 
    # your code here 
Các vấn đề liên quan