使用mockito配置spring-data-jpa業務邏輯層的測試

如果要對service層進行mock測試,首先需要解決的就是autowired的問題,因爲在使用的時候,框架會幫我們解決對象創建的問題,所以我們一般不會預留構造函數,這就給我們mock帶來了一點麻煩。還好,mockito提供瞭解決方案,就是利用@InjectMocks註解:

@InjectMocks - Instantiates testing object instance and tries to inject fields annotated with @Mock or @Spy into private fields of testing object

這個註解會把所有用@Mock@Spy註解的屬性注入到被標記的屬性裏。比如:

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest extends AbstractJUnit4SpringContextTests {
    @Mock
    private UserRegistry userDao;

    @InjectMocks
    private UserService userService;
}

@Service
public class UserService {
    @Autowired
    private UserRegistry userDao;
}

這裏就會把UserRegistry和LoginLogRegistry注入到UserService裏。從名字裏也可以看出,這兩個是DAO層的內容,是在service裏被autowired的。如果這裏報錯的話,之前看到有人說,可以加一個這個,用來初始化mock(雖然我這裏不用):

@Before
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

mock完之後就是測試業務邏輯了。假如service裏有這樣的一個邏輯,判斷是否存在這樣的一個用戶:

@Service
public class UserService {
    @Autowired
    private UserRegistry userDao;

    public boolean hasMatchUser(String userName, String password) {
        long matchCount = userDao.countByUserNameAndPassword(userName, password);
        return matchCount > 0;
    }
}

public interface UserRegistry extends JpaRepository<User, Integer> {
    long countByUserNameAndPassword(String userName, String password);
}

我們的測試代碼可能會這麼寫:

when(userService.hasMatchUser("admin", "123456")).thenReturn(true);

但是如果這麼寫,會報錯:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Boolean cannot be returned by countByUserNameAndPassword()
countByUserNameAndPassword() should return long

“正確”寫法應該是這樣:

doReturn(true).when(userService).hasMatchUser("admin", "123456");

但是這樣仍然會報錯:

org.mockito.exceptions.misusing.NotAMockException: 
Argument passed to when() is not a mock!

因爲service本身不是一個mock過的對象,所以應該把它“變”成一個mockito的對象,但是我們想調用的是真實的service,所以應該用spy而不是mock:

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest extends AbstractJUnit4SpringContextTests {
    @Mock
    private UserRegistry userDao;

    @Spy
    @InjectMocks
    private UserService userService;
}

這樣就能開展正常的測試了。

參考資料

  1. when I run mockito test occurs WrongTypeOfReturnValue Exception
  2. WrongTypeOfReturnValue when nesting when().thenReturn
  3. I get NotAMockException when trying to partially mock a void method - what am I doing wrong?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章