2011-10-18 32 views
6

Câu hỏi của tôi rất giống với vấn đề được nêu ra trong Injecting Mockito mocks into a Spring bean. Trong thực tế, tôi tin rằng câu trả lời được chấp nhận có thể thực sự làm việc cho tôi. Tuy nhiên, tôi đã có một vấn đề với câu trả lời, và sau đó một số giải thích thêm trong trường hợp câu trả lời không có trong thực tế câu trả lời của tôi.Spring + Mockito test injection

Vì vậy, tôi đã theo liên kết trong bài đăng đã nói trên đến trang web Springockito. Tôi thay đổi test-config.xml tôi để bao gồm một cái gì đó tương tự như sau:

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:mockito="http://www.mockito.org/spring/mockito" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.mockito.org/spring/mockito http://www.mockito.org/spring/mockito.xsd"> 

... 

    <mockito:mock id="accountService" class="org.kubek2k.account.DefaultAccountService" /> 
... 
</beans> 

Dường như có cái gì đó sai với hiện www.mockito.org chuyển hướng, vì vậy tôi tìm thấy mã XSD tại https://bitbucket.org/kubek2k/springockito/raw/16143b32095b/src/main/resources/spring/mockito.xsd và thay đổi mục cuối cùng trong xsi: schemaLocation chỉ liên kết bitbucket này.

Chạy mvn test sau đó tạo ra các lỗi sau (dòng mới thêm vào cho dễ đọc):

Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: 
    Line 43 in XML document from class path resource [spring/test-context.xml] is invalid; 
    nested exception is org.xml.sax.SAXParseException; lineNumber: 43; columnNumber: 91; 
    The prefix "mockito" for element "mockito:mock" is not bound. 

Vì vậy, các câu hỏi liên quan Springockito là: Có thể nữa để bao gồm này? Tôi đang thiếu gì?

Bây giờ, trên để giải thích thêm ...

Tôi có một giao diện mà thực hiện Tôi đang cố gắng để kiểm tra:

public interface MobileService { 
    public Login login(Login login); 
    public User getUser(String accessCode, Date birthDate); 
} 

Việc thực hiện có chứa một DAO rằng mùa xuân @Autowire s ở cho tôi :

@Service 
public class MobileServiceImpl implements MobileService { 
    private MobileDao mobileDao; 

    @Autowired 
    public void setMobileDao(MobileDao mobileDao) { 
     this.mobileDao = mobileDao; 
    } 
} 

Tôi không muốn thay đổi giao diện của mình để bao gồm phương thức setMobileDao, vì điều đó sẽ thêm mã chỉ để hỗ trợ đơn vị của tôi thử nghiệm. Tôi đang cố gắng để thử ra DAO kể từ khi SUT thực tế ở đây là ServiceImpl. Làm thế nào tôi có thể đạt được điều này?

Trả lời

9

Bạn không muốn kiểm tra giao diện của mình: nó không chứa mã nào cả. Bạn muốn kiểm tra việc triển khai của mình. Vì vậy, setter có sẵn. Chỉ cần sử dụng:

@Test 
public void testLogin() { 
    MobileServiceImpl toTest = new MobileServiceImpl(); 
    toTest.setMobileDao(mockMobileDao); 
    // TODO call the login method and check that it works as expected. 
} 

Không cần bối cảnh mùa xuân. Chỉ cần instanciate dịch vụ POJO của bạn, tiêm phụ thuộc mock bằng tay, và kiểm tra các phương pháp bạn muốn kiểm tra.

+1

@ Giống như tôi đồng ý, chỉ cần kiểm tra việc triển khai. Không có vấn đề gì để có bối cảnh mùa xuân cho thử nghiệm ** đơn vị **. Và bằng cách này, Mockito cung cấp một số cơ chế tiêm phụ thuộc tầm thường với sự kết hợp của các chú thích '@ Mock' và' @ InjectMocks'. Bạn sẽ thấy [javadoc] tương ứng của họ (http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html). – Brice

0

Bạn có ba tùy chọn để thiết lập dao giả của bạn:

  1. Kiểm tra việc thực hiện - mang đến cho một đường may cho giả của bạn thông qua các phương pháp setDao. (như câu trả lời của JB)
  2. Thêm phương thức setDao vào giao diện - không mong muốn vì bạn không muốn thêm mã chỉ để hỗ trợ các bài kiểm tra của mình.
  3. Thêm hàm tạo vào lớp impl để chấp nhận dao - không mong muốn vì lý do giống như số 2.

Nếu bạn muốn thực hiện # 3, bạn sẽ cần phải thêm một hàm tạo vào MobileService chấp nhận MobileDao.

public MobileServiceImpl(MobileDao mobileDao) { 
    this.mobileDao = mobileDao; 
} 

Sau đó, kiểm tra của bạn sẽ trông như thế này:

import static org.mockito.Mockito.verify; 
import static org.mockito.Mockito.*; 

import java.util.Date; 

import org.junit.Before; 
import org.junit.Test; 

public class MobileServiceImplTest { 

    private MobileService systemUnderTest; 

    private MobileDao mobileDao; 

    @Before 
    public void setup() { 
     mobileDao = mock(MobileDao.class); 
     systemUnderTest = new MobileServiceImpl(mobileDao); 
    } 

    @Test 
    public void testGetUser() { 
     //if you need to, configure mock behavior here. 
     //i.e. when(mobileDao.someMethod(someObject)).thenReturn(someResponse); 
     systemUnderTest.getUser("accessCode", new Date()); 

     verify(mobileDao).getUser("JeffAtwood"); 
    } 
} 

Xin lưu ý rằng bạn đã không cung cấp cho chúng với các chi tiết của MobileDao vì vậy tôi đã tạo ra một phương pháp getUser chấp nhận một String.

Để thực hiện các đường chuyền kiểm tra, MobileServiceImpl của bạn sẽ chỉ cần điều này:

mobileDao.getUser("JeffAtwood"); 
+0

Cũng giống như thêm 'setMobileDao' vào giao diện, thêm một ctor khác để truyền vào đối tượng DAO sẽ thay đổi mã để hỗ trợ kiểm tra đơn vị. Theo câu trả lời của @ jb-nizet, nếu tôi thay đổi thử nghiệm của mình để không sử dụng giao diện nhưng thay vì thực hiện, thì tôi đã có quyền truy cập vào phương thức 'setMobileDao'. – Mike

+0

Hiểu rằng bạn không muốn thêm bất kỳ thứ gì vào mã chỉ để hỗ trợ kiểm tra. Kiểm tra impl thay vì giao diện là một cái gì đó mà tôi đã làm trong quá khứ là tốt;) Chỉ muốn cung cấp cho một tùy chọn khác. –

0

Vấn đề trông giống như classpath của bạn không chứa jar springockito thực tế - Bạn không cần phải thay đổi URL của - đây là những chỉ các thẻ được sử dụng nội bộ vào mùa xuân - chúng không được giải quyết - tất cả những gì bạn cần là bản phân phối Spring đủ mới và springockito trên classpath.

Kuba (tác giả của :) lib nói trên)

0

tôi đã cùng một vấn đề, tôi muốn sử dụng springockito bởi theo wiki nhưng validations lỗi ném xml của họ. Vì vậy, khi tôi cố gắng đi đến các địa điểm nơi xsd được cho là, điều đó đã không xảy ra. Vì vậy, tôi đọc điều này và làm việc với điều này:

xmlns:mockito="http://www.mockito.org/spring/mockito" 
xsi:schemaLocation="http://www.mockito.org/spring/mockito 
    https://bitbucket.org/kubek2k/springockito/raw/16143b32095b/src/main/resources/spring/mockito.xsd"> 

Nhưng khi tôi nhìn vào liên kết này, có cảm giác xấu. Dường như với tôi đó không phải là liên kết ổn định vĩnh viễn (bạn phải kiểm tra xem tôi có sai không)

+0

Dường như liên kết đã bị hỏng ngay bây giờ. Có ai có cái mới không? – schoenk

1

Sau khi đấu tranh với vấn đề Springockito XSD, trong một thời gian, tôi đã tìm thấy một giải pháp đơn giản hơn nhiều. Hãy để mùa xuân tiêm giả cho bạn sử dụng một phương pháp nhà máy, ví dụ: trong applicationContext.xml đặt:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    <bean class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.gerrydevstory.mycoolbank.AccountsDAO"/> 
    </bean> 

    <bean class="com.gerrydevstory.mycoolbank.BankingService"/> 

</beans> 

nơi đậu AccountsDAO được tiêm vào lớp BankingService. Trường hợp kiểm tra JUnit tương ứng là:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/BankingServiceTest.xml") 
public class BankingServiceTest { 

    @Autowired private BankingService bankingService; 
    @Autowired private AccountsDAO mockAccountsDAO; 

    @Test 
    public void testTransfer() throws Exception { 
    // Setup 2 accounts 
    Account acc1 = new Account(); 
    acc1.setBalance(800.00); 
    Account acc2 = new Account(); 
    acc2.setBalance(200.00); 

    // Tell mock DAO to return above accounts when 1011 or 2041 is queried respectively 
    when(mockAccountsDAO.findById(1011)).thenReturn(acc1); 
    when(mockAccountsDAO.findById(2041)).thenReturn(acc2); 

    // Invoke the method to test 
    bankingService.transfer(1011, 2041, 500.00); 

    // Verify the money has been transferred 
    assertEquals(300.00, acc1.getBalance(), 0.001); 
    assertEquals(700.00, acc2.getBalance(), 0.001); 
    } 
} 

Cá nhân tôi thấy điều này rất thanh lịch và dễ hiểu. Để biết thêm chi tiết, hãy xem original blog post.

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