2012-01-12 21 views
10

Làm cách nào để bạn quản lý dữ liệu giả được sử dụng cho thử nghiệm? Giữ chúng với các thực thể tương ứng của chúng? Trong một dự án thử nghiệm riêng biệt? Tải chúng bằng Serializer từ các tài nguyên bên ngoài? Hoặc chỉ cần tạo lại chúng bất cứ nơi nào cần thiết?Dữ liệu giả và chiến lược thử nghiệm đơn vị trong ngăn xếp ứng dụng mô-đun

Chúng tôi có một ngăn xếp ứng dụng với một số mô-đun tùy thuộc vào một mô-đun khác với từng thực thể có chứa. Mỗi mô-đun có các thử nghiệm riêng và cần dữ liệu giả để chạy.

Bây giờ, một mô-đun có nhiều phụ thuộc sẽ cần nhiều dữ liệu giả từ các mô-đun khác. Tuy nhiên, những người này không xuất bản các đối tượng giả của họ vì chúng là một phần của tài nguyên thử nghiệm nên tất cả các mô-đun phải thiết lập tất cả các đối tượng giả mà họ cần lặp đi lặp lại.

Ngoài ra: hầu hết các lĩnh vực vào đơn vị của chúng tôi không nullable để giao dịch thậm chí chạy so với lớp đối tượng đòi hỏi họ phải chứa một số giá trị, phần lớn thời gian với những hạn chế hơn nữa như độc nhất, chiều dài vv

Có cách thực hành tốt nhất trong số này hoặc là tất cả các giải pháp thỏa hiệp?


More Detail

ngăn xếp của chúng tôi trông giống như sau:

Một Module:

src/main/java --> gets jared (.../entities/*.java contains the entities) 
src/main/resources --> gets jared 
src/test/java --> contains dummy object setup, will NOT get jared 
src/test/resources --> not jared 

Chúng tôi sử dụng Maven để xử lý phụ thuộc.

mô-đun dụ:

  • Module Một có một số đối tượng giả
  • Module B cần đối tượng riêng của mình và giống như Module Một

Lựa chọn một)

Mô-đun thử nghiệm T có thể chứa tất cả các đối tượng giả và cung cấp cho chúng trong phạm vi kiểm tra (do đó phụ thuộc tải không bị kẹt) cho tất cả các thử nghiệm trong tất cả các Mô-đun. Công việc vừa ý? Ý nghĩa: Nếu tôi tải TMột và chạy cài đặt trên Một nó sẽ KHÔNG chứa các tham chiếu được giới thiệu bởi T đặc biệt là không B? Sau đó, tuy nhiên A sẽ biết về B datamodel B.

Lựa chọn b)

mô-đun A cung cấp các đối tượng giả ở đâu đó trong src/main/java../entities/dummy phép B để có được chúng trong khi Một không biết về dữ liệu giả B 's

Tùy chọn c)

Mọi mô-đun đều chứa các tài nguyên bên ngoài được các đối tượng giả được tuần tự hóa. Chúng có thể được deserialized bởi môi trường thử nghiệm cần chúng bởi vì nó có sự phụ thuộc vào module mà chúng thuộc về. Điều này sẽ yêu cầu tất cả các mô-đun để tạo và serialize các đối tượng giả của nó mặc dù và làm thế nào sẽ làm điều đó? Nếu với một bài kiểm tra đơn vị khác, nó giới thiệu các phụ thuộc giữa các bài kiểm tra đơn vị mà không bao giờ nên xảy ra hoặc với một kịch bản sẽ khó để gỡ lỗi và không linh hoạt.

Lựa chọn d)

Sử dụng một khuôn khổ giả và giao cho các trường bắt buộc bằng tay cho mỗi bài kiểm tra khi cần thiết. Vấn đề ở đây là hầu hết các trường trong thực thể của chúng ta không phải là nullable và do đó sẽ yêu cầu setters hoặc constructors được gọi để kết thúc chúng ta lại ở đầu một lần nữa.

Những gì chúng ta không muốn

Chúng tôi không muốn thiết lập một cơ sở dữ liệu tĩnh với dữ liệu tĩnh như cấu trúc các đối tượng cần sẽ liên tục thay đổi. Rất nhiều ngay bây giờ, một chút sau đó. Vì vậy, chúng tôi muốn hibernate để thiết lập tất cả các bảng và cột và điền vào những người có dữ liệu tại thời gian thử nghiệm đơn vị. Ngoài ra một cơ sở dữ liệu tĩnh sẽ giới thiệu rất nhiều lỗi tiềm năng và kiểm tra các phụ thuộc lẫn nhau.


Suy nghĩ của tôi có đi đúng hướng không? Cách tốt nhất để giải quyết các bài kiểm tra yêu cầu nhiều dữ liệu là gì? Chúng tôi sẽ có một số mô-đun phụ thuộc lẫn nhau sẽ yêu cầu các đối tượng chứa đầy một số loại dữ liệu từ một số mô-đun khác.


EDIT

Một số thông tin thêm về cách chúng tôi đang làm việc đó ngay bây giờ để đáp ứng với câu trả lời thứ hai:

Vì vậy, để đơn giản, chúng tôi có ba mô-đun: Person, Product, Order. Person sẽ kiểm tra một số phương pháp quản lý sử dụng một đối tượng MockPerson:

(trong người/src/kiểm tra/java :)

public class MockPerson { 

    public Person mockPerson(parameters...) { 
     return mockedPerson; 
    } 
} 

public class TestPerson() { 
    @Inject 
    private MockPerson mockPerson; 
    public testCreate() { 
     Person person = mockPerson.mockPerson(...); 
     // Asserts... 
    } 
} 

Lớp MockPerson sẽ không được đóng gói.

cũng áp dụng cho thử nghiệm sản phẩm:

(trong sản phẩm /src/kiểm tra/java :)

public class MockProduct() { ... } 
public class TestProduct { 
    @Inject 
    private MockProduct mockProduct; 
    // ... 
} 

MockProduct là cần thiết nhưng sẽ không được đóng gói.

Bây giờ, Kiểm tra đơn đặt hàng sẽ yêu cầu MockPersonMockProduct, vì vậy hiện tại chúng tôi cần tạo cả hai cũng như MockOrder để kiểm tra Order.

(trong trật tự/src/kiểm tra/java :)

Đây là những bản sao và sẽ cần phải được thay đổi mỗi khi Person hoặc Product thay đổi

public class MockProduct() { ... } 
public class MockPerson() { ... } 

Đây là lớp học chỉ phải ở đây:

public class MockOrder() { ... } 

public class TestOrder() { 
    @Inject 
    private order.MockPerson mockPerson; 
    @Inject 
    private order.MockProduct mockProduct; 
    @Inject 
    private order.MockOrder mockOrder; 
    public testCreate() { 

     Order order = mockOrder.mockOrder(mockPerson.mockPerson(), mockProduct.mockProduct()); 
     // Asserts... 
    } 
} 

Bộ điều khiển hiện tại, chúng tôi phải cập nhật person.MockPersonorder.MockPerson bất cứ khi nào Person bị thay đổi. Không phải là nó tốt hơn để chỉ xuất bản các Mocks với bình để mọi thử nghiệm khác mà có sự phụ thuộc anyway chỉ có thể gọi Mock.mock và có được một đối tượng thiết lập độc đáo không? Có phải không? Hay đây là mặt tối - một cách dễ dàng?

Trả lời

3

Điều này có thể hoặc có thể không áp dụng - Tôi tò mò muốn xem ví dụ về các đối tượng giả và mã thiết lập liên quan. (Để có một ý tưởng tốt hơn về việc liệu nó có áp dụng cho tình huống của bạn không.) Nhưng những gì tôi đã làm trong quá khứ thậm chí không giới thiệu loại mã này vào các bài kiểm tra. Như bạn mô tả, thật khó để sản xuất, gỡ lỗi, và đặc biệt là gói và duy trì.

Những gì tôi đã usaully thực hiện (và AFAIKT trong Java đây là thực hành tốt nhất) là cố gắng sử dụng các mô hình dữ liệu thử nghiệm Builder, như mô tả của Nat Pryce trong bài Test Data Builders mình.

Nếu bạn nghĩ rằng đây là phần nào liên quan, kiểm tra những hiểu:

+0

Hey cwash! Cảm ơn cho con trỏ nhà máy. Tôi nhớ sử dụng nó trong một hướng dẫn đường ray;) Đây có thể là giải pháp, tôi sẽ phải kiểm tra nó ra xa hơn. – Pete

+0

@Pete - tuyệt, bạn có thể để lại ghi chú/cập nhật cho chúng tôi biết bạn đã quyết định điều gì không? – cwash

+0

Vì vậy, có vẻ như chúng ta có thể sử dụng nó như một nhà cung cấp dữ liệu giả trung tâm. Tuy nhiên, cuối cùng nó chỉ là Option a) có nghĩa là một số dự án bên ngoài sẽ giữ tất cả các trình tạo dữ liệu cần thiết. Vẫn tự hỏi nếu đó là cách tốt nhất để đi. Hy vọng sẽ có thêm một số ý kiến ​​về điều này .. – Pete

1

Tôi tự hỏi nếu bạn không thể giải quyết vấn đề của mình bằng cách thay đổi phương pháp thử nghiệm của bạn.

Đơn vị Thử nghiệm một mô-đun phụ thuộc vào các mô-đun khác và, do đó, trên dữ liệu thử nghiệm của các mô-đun khác không phải là một thử nghiệm đơn vị thực tế!

Điều gì sẽ xảy ra nếu bạn tiêm một mô hình cho tất cả các phụ thuộc của mô-đun của bạn đang được kiểm tra để bạn có thể kiểm tra nó hoàn toàn tách biệt. Sau đó, bạn không cần phải thiết lập một môi trường hoàn chỉnh mà mỗi mô-đun phụ thuộc có dữ liệu cần thiết, bạn chỉ thiết lập dữ liệu cho mô-đun mà bạn thực sự thử nghiệm.

Nếu bạn hình dung kim tự tháp, thì cơ sở sẽ là các thử nghiệm đơn vị của bạn, ở trên bạn có thử nghiệm chức năng và ở trên cùng bạn có một số thử nghiệm kịch bản (hoặc như Google gọi chúng, thử nghiệm nhỏ, trung bình và lớn).

Bạn sẽ có một số lượng lớn các Bài kiểm tra đơn vị có thể kiểm tra mọi đường dẫn mã vì các phụ thuộc giả lập có thể cấu hình hoàn toàn. Sau đó, bạn có thể tin tưởng vào các bộ phận riêng của bạn và điều duy nhất mà các bài kiểm tra chức năng và kịch bản của bạn sẽ làm là kiểm tra xem mỗi mô-đun có được nối đúng với các mô-đun khác hay không.

Điều này có nghĩa là dữ liệu thử nghiệm mô-đun của bạn không được chia sẻ bởi tất cả các thử nghiệm của bạn mà chỉ bởi một số được nhóm lại với nhau.

Mẫu trình xây dựng như được đề cập bởi cwash chắc chắn sẽ giúp ích trong các bài kiểm tra chức năng của bạn. Chúng tôi đang sử dụng .NET Builder được cấu hình để xây dựng một cây đối tượng hoàn chỉnh và tạo ra các giá trị mặc định cho mỗi thuộc tính, vì vậy khi chúng ta lưu nó vào cơ sở dữ liệu, tất cả dữ liệu bắt buộc đều có mặt.

+0

Cảm ơn câu trả lời của bạn. Bạn có thể cung cấp một số mã giả để hiểu rõ hơn không? Ít nhất là cho phần thử nghiệm đơn vị. Chúng tôi chưa thực hiện thử nghiệm chức năng và kịch bản. Theo như tôi hiểu bạn, chúng tôi đang làm những gì bạn đang nói ngay bây giờ. Mỗi Module có các lớp Mock cung cấp dữ liệu có thể cấu hình và được tiêm vào các bộ thử nghiệm. Mỗi bài kiểm tra sau đó gọi đối tượng giả để tạo dữ liệu cần thiết. Tôi sẽ cung cấp một số mã nguồn và nhiều thông tin khác để vạch ra cách tiếp cận và mối quan tâm của chúng tôi chi tiết hơn để bạn có thể kiểm tra xem đó là những gì bạn đang nói đến. – Pete

+0

@Pete Tôi không có nhà phát triển java để bạn có thể vui lòng giải thích những gì bạn có ý nghĩa với: 'Vấn đề là, bây giờ chúng ta phải cập nhật person.MockPerson và order.MockPerson bất cứ khi nào người được thay đổi.' Bạn phải thay đổi điều gì? Bạn không chỉ giả định các thuộc tính và phương pháp quan trọng? –

+0

Có lẽ câu hỏi của tôi quá dài tổng thể nên thật khó để chọn ra các chi tiết cần thiết. Xin lỗi ... Tôi đã mô tả cách chúng tôi phải giả lập tất cả các trường như hầu hết là 'nullable = false'. Vì vậy, nếu tôi thêm một cột mới vào thực thể 'Person', tôi sẽ phải thêm mocking cho tất cả các lần xuất hiện của MockPerson trong mỗi mô-đun. – Pete

3

Vâng, tôi đã đọc kỹ tất cả các đánh giá cho đến nay và đó là câu hỏi rất hay. Tôi thấy các phương pháp tiếp cận sau cho sự cố:

  1. Thiết lập cơ sở dữ liệu thử nghiệm (tĩnh);
  2. Mỗi thử nghiệm có dữ liệu thiết lập riêng tạo dữ liệu thử nghiệm (động) trước khi chạy thử nghiệm đơn vị;
  3. Sử dụng đối tượng giả hoặc giả. Tất cả các mô-đun đều biết tất cả các đối tượng giả, cách này không có bản sao;
  4. Giảm phạm vi kiểm tra đơn vị;

Tùy chọn đầu tiên khá thẳng về phía trước và có nhiều nhược điểm, ai đó phải tái tạo nó một lần trong khi khi kiểm tra đơn vị "lộn xộn", nếu có thay đổi trong mô-đun dữ liệu, ai đó phải giới thiệu tương ứng thay đổi dữ liệu thử nghiệm, rất nhiều chi phí bảo trì. Không phải để nói rằng thế hệ của dữ liệu này trên tay đầu tiên có thể khó khăn. Xem tùy chọn thứ hai.

Tùy chọn thứ hai, bạn viết mã thử nghiệm trước khi thử nghiệm gọi một số phương pháp kinh doanh "cốt lõi" của bạn tạo ra thực thể của bạn. Lý tưởng nhất, mã kiểm tra của bạn phải độc lập với mã sản xuất, nhưng trong trường hợp này, bạn sẽ kết thúc với mã trùng lặp, bạn nên hỗ trợ hai lần. Đôi khi, bạn nên chia nhỏ phương thức kinh doanh sản xuất để có điểm vào cho bài kiểm tra đơn vị của bạn (tôi làm cho các phương thức đó riêng tư và sử dụng Reflection để gọi chúng, cũng có một số nhận xét về phương pháp cần thiết, tái cấu trúc bây giờ là một chút khó) . Hạn chế chính mà nếu bạn phải thay đổi phương pháp kinh doanh "cốt lõi" của bạn, nó đột nhiên ảnh hưởng đến tất cả các thử nghiệm đơn vị của bạn và bạn không thể kiểm tra. Vì vậy, các nhà phát triển cần phải nhận thức được nó và không làm cho partials cam kết các phương pháp kinh doanh "cốt lõi", trừ khi họ làm việc. Ngoài ra, với bất kỳ thay đổi nào trong lĩnh vực này, bạn nên ghi nhớ "nó sẽ ảnh hưởng đến bài kiểm tra đơn vị của tôi như thế nào". Đôi khi, cũng không thể sao chép tất cả các dữ liệu cần thiết một cách linh động (thông thường, đó là do API của bên thứ ba, ví dụ, bạn gọi một ứng dụng khác với DB của chính nó mà bạn yêu cầu sử dụng một số khóa. dữ liệu được liên kết) được tạo thủ công thông qua ứng dụng của bên thứ ba. Trong trường hợp này, dữ liệu này và chỉ dữ liệu này sẽ được tạo tĩnh. Ví dụ: 10000 khóa được tạo của bạn bắt đầu từ 300000.

Tùy chọn thứ ba nên tốt Tùy chọn a) và d) âm thanh cho tôi khá tốt. Đối với đối tượng giả của bạn, bạn có thể sử dụng khung giả hoặc bạn không thể sử dụng nó. Mock Framework là ở đây chỉ để giúp bạn. Tôi không thấy vấn đề mà tất cả các đơn vị của bạn biết tất cả các thực thể của bạn.

Tùy chọn thứ tư có nghĩa là bạn xác định lại "đơn vị" trong bài kiểm tra đơn vị của bạn là gì.Khi bạn có vài mô-đun với sự phụ thuộc lẫn nhau hơn có thể khó kiểm tra từng mô-đun trong sự cô lập. Cách tiếp cận này nói rằng, những gì chúng tôi thử nghiệm ban đầu là kiểm tra tích hợp và không phải kiểm tra đơn vị. Vì vậy, chúng tôi chia các phương pháp của chúng tôi, trích xuất "đơn vị công trình" nhỏ nhận được tất cả sự phụ thuộc lẫn nhau của nó vào một mô-đun khác làm tham số. Các thông số này có thể được (hy vọng) dễ dàng chế nhạo. Hạn chế chính của phương pháp này là bạn không kiểm tra tất cả mã của mình, nhưng chỉ để nói, "tiêu điểm". Bạn cần thực hiện kiểm tra tích hợp riêng (thường là bởi nhóm QA).

+0

Hey! Cảm ơn các đầu vào. Đặc biệt là lựa chọn thứ 4 là thú vị. Bạn nói đúng, những gì chúng tôi làm không thực sự là thử nghiệm đơn vị nhưng thử nghiệm tích hợp, vì chúng tôi gọi các hàm quản lý từ các mô-đun thấp hơn để tạo các đối tượng cần thiết tại một thử nghiệm đơn vị trong mô-đun cao hơn, do đó ngầm kiểm tra một số chức năng của mô-đun thấp hơn. Tôi nhận ra điều này làm cho các bài kiểm tra không hoàn toàn độc lập. Tôi nghĩ rằng chúng tôi nghĩ rằng: oh tốt, sau đó nó sẽ chỉ tăng mật độ thử nghiệm cho tất cả các mô-đun. Tôi nghĩ rằng tôi nên đọc về tính hữu ích của các bài kiểm tra đơn vị và các bài kiểm tra tích hợp ... – Pete

+1

@Pete đó chính xác là vấn đề. Bạn cần phải chắc chắn rằng bạn có thể kiểm tra các chức năng của bạn trong sự cô lập. Mocking ra mọi phụ thuộc và sử dụng một Builder để tạo ra dữ liệu thử nghiệm. Ngoài ra hãy chắc chắn rằng bạn giữ Luật Demeter trong tâm trí (không đi qua một khách hàng toàn bộ khi bạn chỉ cần địa chỉ) bởi vì điều đó sẽ làm cho mã của bạn tốt hơn nhiều testable. –

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