2012-02-10 23 views
5

Tôi mới làm quen với khung công tác lò xo và có câu hỏi về khả năng tiêm phụ thuộc của nó bằng cách sử dụng bối cảnh mùa xuân.Tạo một cá thể đậu mới sau mỗi lần kiểm tra đơn vị

Đây là lớp học Tôi cố gắng để viết một bài kiểm tra tích hợp cho:

public class UserService { 

private Validator validator; 
private UserRepository userRepository; 
private Encryptor encryptor; 
private MailService mailService; 

... 

public void registerUser(User user) { 
    user.setPassword(encryptor.encrypt(user.getPassword())); 

    Errors errors = new BindException(user, "user"); 
    validator.validate(user, errors); 

    if (errors.getErrorCount() == 0) { 
     userRepository.addUser(user); 
     mailService.sendMail(user.getEmail()); 
    } 
} 

Trong các thử nghiệm của tôi (sử dụng Mockito) Tôi muốn đảm bảo với bốn mục được gọi là như vậy tôi có thể tạo các xét nghiệm như:

public void testRegisterCallsValidateInValidator() { 
    userService.registerUser(testUser); 
    verify(userService.getValidator(), times(1)).validate(any(User.class), any(Errors.class)); 
} 

Tất cả các thử nghiệm đều thất bại khi nói rằng tôi đã gọi phương thức nhiều lần. Đoán duy nhất của tôi là bean UserService được tạo một lần ở đầu tất cả các thử nghiệm nhưng không được tải lại sau mỗi lần kiểm tra.

Trong cấu hình thử nghiệm của tôi tôi sử dụng xml sau đây để quyết định đậu để tiêm:

<bean id="userService" class="be.kdg.coportio.services.UserService"> 
    <property name="validator" ref="validator"/> 
    <property name="userRepository" ref="userRepository"/> 
    <property name="encryptor" ref="encryptor"/> 
    <property name="mailService" ref="mailService"/> 
</bean> 

Bất kỳ ý tưởng?

+0

bạn có nhiều phương pháp thử hay chỉ một phương pháp bạn đã dán? – ggreiner

+0

Tôi có bốn phương pháp thử nghiệm (1 trong số đó tôi đã dán). Tôi nhận được ba bài kiểm tra thất bại nói rằng tôi đã gọi các phương pháp tôi đang cố gắng để kiểm tra tương ứng 2, 3 và 4 lần. – geoffreydv

Trả lời

6

Để Unit và Tích hợp kiểm tra rõ ràng riêng biệt (bỏ qua các cuộc tranh luận ý nghĩa của từng danh mục) - bạn có thể thử nghiệm dịch vụ của mình theo hai cách:

  • qua thử nghiệm Tích hợp - bạn kích hoạt toàn bộ Ngữ cảnh mùa xuân và kiểm tra dịch vụ như một hạt đơn.
  • qua bài kiểm tra Đơn vị - bạn chỉ cần khởi tạo dịch vụ cho chính mình, giả sử những gì cần được mô phỏng, không cần Spring.

Đề xuất của tôi không phải là kết hợp Spring và mocks nếu bạn có thể giúp nó - giữ Mockito cho các bài kiểm tra đơn vị (đó là những gì bạn cần bằng giao diện của nó) và sử dụng các bài kiểm tra tích hợp khởi động toàn bộ bối cảnh mùa xuân để kiểm tra những thứ khác - mối quan tâm dai dẳng, giao dịch, v.v.

Bạn không cần Spring để thử các cộng tác viên của một lớp và thực hiện thử nghiệm tương tác đơn giản với Mockito.

+1

"Đề nghị của tôi không phải là để trộn Spring và mocks nếu bạn có thể giúp nó" chính xác. Tiêm mocks của bạn theo cách thủ công nếu bạn có các bộ định cư hoặc sử dụng phương thức 'ReflectionTestUtils.setField()' của Spring. Không cần phải kích hoạt bối cảnh mùa xuân nếu dịch vụ của bạn thay đổi cho mọi thử nghiệm –

+0

Lời khuyên của bạn đã giúp tôi làm sáng tỏ một số điều. Tôi đã lạm dụng từ "kiểm tra tích hợp" trong khi tôi thực sự có nghĩa là thử nghiệm tương tác. Ban đầu tôi đã chọn không sử dụng mùa xuân để tiêm các mocks của tôi vì vậy tôi đang chuyển về mã đó ngay bây giờ, chỉ sử dụng lò xo để kiểm tra tích hợp thực sự. Cảm ơn! – geoffreydv

2

trong phương thức @Before của bạn, hãy nhớ đặt lại các đối tượng giả của bạn.

@Before 
public void setup(){ 
    Mockito.reset(validator); 
} 
+0

Đối với một số lý do, một trong các bài kiểm tra hiện đã được sửa nhưng những người khác vẫn không thành công (cùng một thông báo như trước). Tôi đã đặt 4 dòng trong phương thức thiết lập như sau: Mockito.reset (userService.getValidator()); Có lẽ nó thất bại vì tôi đang sử dụng một getter? Tôi chỉ có một thuộc tính trong lớp kiểm tra cho UserService, không phải cho 4 đối tượng riêng lẻ. – geoffreydv

0

Bạn có thể thử gọi setDirty (true) trong phương pháp thử để tải lại ngữ cảnh Spring.

0

Tôi chưa bao giờ sử dụng Mockito, nhưng Spring-Beans là Singletons theo mặc định - vì vậy chúng sẽ không được tạo lại trừ khi bạn gọi refresh() trên Spring-Container.

Nếu bạn anyways không cần họ được Singletons, bạn có thể thiết lập phạm vi của họ để prototype mà sẽ tạo ra mới đậu-trường hợp trên tất cả các tiêm ...

24

Bạn đang sử dụng lại ngữ cảnh của mình, để có các bài kiểm tra độc lập với nhau, bạn có thể cần làm mới ngữ cảnh của mình sau mỗi lần kiểm tra để đặt lại mọi thứ.

Tôi giả sử bạn đang sử dụng Junit 4.5+. Nó sẽ tương tự với các khuôn khổ thử nghiệm khác.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations={"mycontext.xml"}) 
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) 
public class MyTestClass { 
... 
    // my tests  
... 
} 

Bạn có thể đặt các @DirtiesContext ở cấp phương pháp nếu các phương pháp mà cần "sửa chữa" rất ít, nhưng nếu bạn đang sử dụng Spring lựa chọn tốt nhất của bạn là để làm điều đó sau mỗi lần kiểm tra.

Dù sao, tôi không nghĩ rằng bạn nên sử dụng mocks/gián điệp trong các thử nghiệm hội nhập:

  • Trong các thử nghiệm đơn vị, sử dụng mocks (nếu bạn muốn) và bơm tay. Ở đây bạn muốn xác minh hành vi của đậu thử nghiệm của bạn như là một đơn vị, vì vậy bạn cô lập nó từ phần còn lại bằng cách sử dụng mocks. Điều này cũng có lợi thế là JUnit cô lập các bài kiểm tra của bạn bằng cách sử dụng một thể hiện khác của lớp kiểm tra cho mỗi bài kiểm tra, vì vậy trừ khi bạn sử dụng static hoặc các thực hành thử nghiệm không thân thiện khác, mọi thứ sẽ hoạt động.

  • Trong thử nghiệm tích hợp, hãy sử dụng đậu thực và cho phép tiêm vào mùa xuân. Ở đây mục tiêu là để xác minh rằng đậu tương tác tốt với nhau/với môi trường (cơ sở dữ liệu, mạng, ...) Bạn làm không phải muốn tách đậu ở đây, vì vậy bạn không nên sử dụng mocks.

Xem Spring documentation about testing để được giải thích chi tiết hơn.

+0

Cảm ơn ví dụ về mã. Như tôi đã bình luận về câu trả lời của Eugen, tôi trộn hai loại bài kiểm tra lên. Đây là những gì tôi sẽ sử dụng trong các bài kiểm tra tích hợp thực sự của tôi :) – geoffreydv

+0

Cảm ơn bạn rất nhiều. Điều này cũng có thể được áp dụng trên các TestNG-Testclasses mở rộng 'AbstractTestNGSpringContextTests'. –

+0

AFTER_EACH_TEST_METHOD, thật tuyệt vời. Điều này thực sự giúp với các đối tượng trang mới cho mỗi bài kiểm tra của tôi. – Will