Sprigboot+Junit+Mockitoによるユニットテストの例
前言
この文章はSpringboot+Junnit+Mockitoを使ってセルテストをする方法を紹介します。ケースは取引の種類を選んでユニットテストをします。
ユニットテスト前に需要を理解する
良いテストを書くには、まず需要を理解しなければなりません。何をすれば測定が分かりますか?しかし、本文は主にmockitoの使い方を話しています。具体的な需要に注目する必要はありません。したがって、この節は具体的な需要説明を省略する。
外部依存を遮断する
Case 1.被測定類に@Autowiredまたは@Resource注で表示されている依存対象は、戻り値をどのように制御しますか?
測定方法Match ingServiceImpl.javaのmatchingを例にとって
被測定類Match ingServiceImpl
テストクラスMatch ServiceImplTest
例えば、Match ingServiceImplにはstartBuyProcessという関数がありますが、その中にはこのクラスの他の関数が呼び出されています。例えば、getTopSellOrder、matchingは、この2つの関数の戻り値をどのように制御しますか?
ここで解決したい問題は、どのように一つのクラスの「部分mock」Cの測定方法(例えば、startByProcess)を実行しますか?他の方法(例えば、get TopSellOrder)は杭を打ちます。
被測定類Match ingServiceImpl
テストクラスMatch ServiceImplTest.testStartBuy Process_InCaseOfMatch Success
testStartBuyProcess_InCaseOfMatch Successの目的はdoMatch ingSuccessを測定することです。私たちは前の準備を全部終わらせてから、doMatch Successを測定することができます。
もっと良い実践は別のテスト方法で単独でdoMatch Successを測定するべきです。注目点も多く集中しています。doMatch Successがカバーされました。startBuyProcessは実際にはそれ自体の判断分岐をカバーするだけでいいです。カバー率は同じです。テストコードも維持しやすいです。testStartBuy Process。InCaseOfMatch Successは考えすぎる職責のため、変化の影響を受けやすく、細かいものが変わると、正常な仕事に影響を与える可能性があります。
テストフレーム導入のMaven依存
Mockito BasedTest
この文章はSpringboot+Junnit+Mockitoを使ってセルテストをする方法を紹介します。ケースは取引の種類を選んでユニットテストをします。
ユニットテスト前に需要を理解する
良いテストを書くには、まず需要を理解しなければなりません。何をすれば測定が分かりますか?しかし、本文は主にmockitoの使い方を話しています。具体的な需要に注目する必要はありません。したがって、この節は具体的な需要説明を省略する。
外部依存を遮断する
Case 1.被測定類に@Autowiredまたは@Resource注で表示されている依存対象は、戻り値をどのように制御しますか?
測定方法Match ingServiceImpl.javaのmatchingを例にとって
被測定類Match ingServiceImpl
public class MatchingServiceImpl implements MatchingService {
private static final Logger log = LoggerFactory.getLogger(MatchingServiceImpl.class);
@Autowired
private QuoteService quoteService;
...
public MatchingResult matching(MatchingOrder buyOrder, MatchingOrder sellOrder) {
int currentPrice = quoteService.getCurrentPriceByProduct(buyOrder.getProductCode());
MatchingResult result = new MatchingResult();
if (sellOrder != null && buyOrder != null &&
sellOrder.getPrice() <= buyOrder.getPrice()) {
...
}
}
matching方法における「teService.get Currenent PriceByProduct」;Redisにアクセスして現在のオファーを取得したいです。ここでは外部依存の「Service mock」を落として、get Current PriceByProduct方法の戻り値を制御します。mockitoを使うとできます。具体的には以下の通りです。テストクラスMatch ServiceImplTest
public class MatchingServiceImplTest extends MockitoBasedTest {
/**
* @Mock @InjectMocks
*/
@Mock
private QuoteService quoteService;
/**
* <pre>
* , @InjectMocks , @mock 。
* MatchingServiceImpl new (Mockito 1.9 new ), spring 。 spring
* , database ,redis ,zookeeper,mq, , new
* </pre>
*/
@InjectMocks
private MatchingServiceImpl matchingService = new MatchingServiceImpl();
@Test
public void testMatching_SuccessWhenCurrentPriceBetweenBuyPriceAndSellPrice() {
MatchingOrder buyOrder = new MatchingOrder();
buyOrder.setPrice(1000);
buyOrder.setCount(23);
MatchingOrder sellOrder = new MatchingOrder();
sellOrder.setPrice(800);
sellOrder.setCount(20);
// (Method stubbing)
// when(x).thenReturn(y) :
Mockito.when(quoteService.getCurrentPriceByProduct(Mockito.anyString())).thenReturn(900);
MatchingResult result = matchingService.matching(buyOrder, sellOrder);
org.junit.Assert.assertEquals(true, result.isSuccess());//
org.junit.Assert.assertEquals(20, result.getTradeCount());//
org.junit.Assert.assertEquals(900, result.getTradePrice()); //
}
Case 2.被測定関数Aは、測定されたクラスの他の関数Bを呼び出して、関数Bの戻り値をどのように制御しますか?例えば、Match ingServiceImplにはstartBuyProcessという関数がありますが、その中にはこのクラスの他の関数が呼び出されています。例えば、getTopSellOrder、matchingは、この2つの関数の戻り値をどのように制御しますか?
ここで解決したい問題は、どのように一つのクラスの「部分mock」Cの測定方法(例えば、startByProcess)を実行しますか?他の方法(例えば、get TopSellOrder)は杭を打ちます。
被測定類Match ingServiceImpl
protected void startBuyProcess(MatchingOrder buyOrder, boolean waitForMatching) {
while (true) {
//
MatchingOrder topSellOrder = getTopSellOrder(buyOrder.getProductCode());
MatchingResult matchingResult = matching(buyOrder,topSellOrder);
if(matchingResult.isSuccess()) {
doMatchingSuccess(buyOrder,topSellOrder,matchingResult,MatchingType.BUY);
if(buyOrder.getCount() <= 0) {
break;
}
}else {
if(waitForMatching) {
//
addToMatchingBuy(buyOrder);
}else {
//
sendCancleMsg(buyOrder);
}
break;
}
}
}
Mockito.spyを利用して「部分的なMock」ができます。テストクラスMatch ServiceImplTest.testStartBuy Process_InCaseOfMatch Success
/**
*
* StartBuyProcess , startBuyProcess
* {@link MatchingServiceImpl#startBuyProcess(MatchingOrder, boolean)}
*
* <pre>
* if (matchingResult.isSuccess()) {
*
* doMatchingSuccess(buyOrder, topSellOrder, matchingResult, MatchingType.BUY);
*
* if (buyOrder.getCount() <= 0) {
* break;
* }
* }
* </pre>
*
*/
@Test
public void testStartBuyProcess_InCaseOfMatchingSuccess() {
MatchingOrder buyOrder = new MatchingOrder();
buyOrder.setPrice(700);
buyOrder.setCount(23);
// Mockito.spy() matchingService
matchingService = Mockito.spy(matchingService);
MatchingResult firstMatchingResult = new MatchingResult();
firstMatchingResult.setSuccess(true);
firstMatchingResult.setTradeCount(20);
MatchingResult secondMatchingResult = new MatchingResult();
secondMatchingResult.setSuccess(false);
// doReturn(x).when(obj).method() , , ,
// doReturn matchingService.matching firstMatchingResult, secondMatchingResult
// startBuyProcess while , matching
Mockito.doReturn(firstMatchingResult).doReturn(secondMatchingResult).when(matchingService)
.matching(Mockito.any(MatchingOrder.class), Mockito.any(MatchingOrder.class));
MatchingOrder sellOrder = new MatchingOrder();
sellOrder.setPrice(600);
sellOrder.setCount(20);
// getTopSellOrder
Mockito.doReturn(sellOrder).when(matchingService).getTopSellOrder(Mockito.anyString());
// jedis
Mockito.when(jedisClient.incrBy(Mockito.anyString(), Mockito.anyLong())).thenReturn(0L);
// startBuyProcess , ,
matchingService.startBuyProcess(buyOrder, true);
// doMatchingSuccess ,
// verify , , jedisClient.zremFirst 1
Mockito.verify(jedisClient, Mockito.times(1)).zremFirst(Mockito.anyString());
org.junit.Assert.assertEquals(3, buyOrder.getCount());
org.junit.Assert.assertEquals(0, sellOrder.getCount());
}
spyの使い方はもうデモンストレーション済みです。以下はtestStartBuy Processから。InCaseOfMatch Successはユニットテストの「粒度」を言います。testStartBuyProcess_InCaseOfMatch Successの目的はdoMatch ingSuccessを測定することです。私たちは前の準備を全部終わらせてから、doMatch Successを測定することができます。
もっと良い実践は別のテスト方法で単独でdoMatch Successを測定するべきです。注目点も多く集中しています。doMatch Successがカバーされました。startBuyProcessは実際にはそれ自体の判断分岐をカバーするだけでいいです。カバー率は同じです。テストコードも維持しやすいです。testStartBuy Process。InCaseOfMatch Successは考えすぎる職責のため、変化の影響を受けやすく、細かいものが変わると、正常な仕事に影響を与える可能性があります。
テストフレーム導入のMaven依存
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
<scope>test</scope>
</dependency>
springboot+junnit+mockitoのコンテキスト構築Mockito BasedTest
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestApplication.class)
public abstract class MockitoBasedTest {
@Before
public void setUp() throws Exception {
// Mockito
MockitoAnnotations.initMocks(this);
}
}
// MockitoBasedTest
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。