Prefácio
Este artigo apresenta como usar o SpringBoot+Junit+Mockito para testes de unidade e selecione uma classe que corresponda às transações para fazer testes de unidade.
Entenda os requisitos antes do teste de unidade
Para escrever um bom teste único, você deve primeiro entender os requisitos. Somente sabendo o que fazer, você pode saber testar. Mas este artigo fala principalmente sobre o uso do Mockito, e não há necessidade de prestar atenção às necessidades específicas. Portanto, esta seção omite a descrição de requisitos específicos.
Isolar dependências externas
Case1. Como controlar o valor de retorno do objeto de dependência anotado por @Autowired ou @Resource Anotation na classe testada
Tomando o Matching (MatchingOrder Buyorder, MatchingOrder Sellorder) do método em Test MatchingServiceImpl.java como exemplo
MatchingServiceImpl de classe testado
classe pública MatchingServiceImpl implementa o MatchingService {private estático final logger log = loggerFactory.getLogger (MatchingServiceImpl.class); @Autowired Private QuotService QuotService; ... MatchingResult de correspondência pública (MatchingOrder BuyOrder, MatchingOrder SellOrder) {int currentPrice = QuotService.GetCurrentPriceByProduct (BuyOrder.getProductCode ()); MatchingResult resultado = new MatchingResult (); if (SellOrder! = NULL && Buyorder! = NULL && SellOrder.getPrice () <= Buyorder.getPrice ()) {...}}QuotService.getCurrentPriceByProduct (BuyOrder.getProductCode ()); Para acessar o Redis para obter a cotação atual, precisamos zombar do serviço de dependência externo para controlar o valor de retorno do método getCurrentPriceByProduct. Você pode fazer isso usando o Mockito, como segue:
Classe de teste MatchingServiceImpltest
classe pública MatchingServiceImpltest estende o mockitobasedtest { / *** Os objetos marcados por @mock serão automaticamente injetados no objeto marcado por @injectMocks* / @mock private QuotService QuotService; /** * <pre> * objetos a serem testados, marcados com @injectMocks, esses objetos marcados por @mock serão injetados automaticamente nele. * Outro ponto de nota é que o MatchingServiceImpl é diretamente novo (está ok se não for novo após o Mockito 1.9), em vez de injetado através do recipiente da mola. Porque aqui não preciso obter outras dependências do contêiner da mola *, e não preciso de banco de dados, redis, zookeeper, MQ e nada depende disso, então eu diretamente novo *</pre> */ @injectmocks private MatchingServiceImpl MatchingService = novo MatchingSericeImpl (); @Test public void testmatching_successwencurrentpricebetweenbuypriceandSellPrice () {MatchingOrder BuyDorder = new Matchingorder (); BuyOrder.setPrice (1000); BuyOrder.setCount (23); MatchandOrder SellOrder = New Matchingorder (); SellOrder.setPrice (800); SellOrder.setCount (20); // Método Stubbing (Method Stubbing) // Quando (x) .ThenReTurn (y): retorna o valor especificado quando o método especificado é chamado Mockito.When (QuotService.GetCurrentPriceByProduct (Mockito.Anystring ()). MatchingResult resultado = MatchingService.Matching (BuyDorde, SellOrder); org.junit.assert.asserTequals (true, resultado.ISSUCCESS ()); // afirma se a correspondência é bem -sucedida org.junit.assert.asserTequals (20, resultado.EstradeCount (); // afirmam a quantidade de transações org.junit.assert. (900); // afirma se a citação mais recente atende às expectativas}Case2. Quando a função A é testada, como controlar o valor de retorno da função B na classe em teste?
Por exemplo, existe uma função StartBuyProcess no MatchingServiceImpl, que chama outras funções da classe, como GetTopsEllOrder e correspondência. Como controlar os valores de retorno dessas duas funções?
O problema a ser resolvido aqui é como realmente executar o método medido (como o StartBuyProcess) de uma classe "Mock parcial" de classe, enquanto outros métodos (como GetTopsEllorder) são empilhados (não entrando e executado realmente).
MatchingServiceImpl de classe testado
Void protegido StartBuyProcess (MatchingOrder Buyorder, Boolean WaitFormatching) {while (true) {// O melhor preço da contraparte 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) {// Adicionar para corresponder à fila a ser correspondente AddTomatchingBuy (BuyDorde); } else {// revoga o pedido sendCanclemsg (BuyDorde); } quebrar; }}}}Usar Mockito.spy () pode alcançar "Mock Parcial"
Classe de teste MatchingServiceImpltest.teststartBuyProcess_incaseofMatchingsuccess
/** * * Teste se o processamento do método startBuyprocess após a correspondência bem -sucedida atende às expectativas, ou seja, teste o comportamento após a entrada do ramo de julgamento a seguir * {@link MatchingServiceImpl#startbuyprocess (MatchandOrder, boolean)} * * * * if (matchingResult.issuccess (),), {boolean)} * * * * se (matchingResult.issuccess) { MatchingResult, MatchingType.buy); * * if (BuyOrder.getCount () <= 0) { * Break; *} *} * </pre> * */ @Test public void testStartBuyProcess_incaseofMatchingsuccess () {MatchingOrder Buyorder = new Matchingorter (); BuyOrder.setPrice (700); BuyOrder.setCount (23); // usa Mockito.spy () para travessem parcialmente o MatchingService MatchingService = Mockito.spy (MatchingService); MatchingResult FirstMatchingResult = new MatchingResult (); FirstMatchingResult.SetSuccess (true); FirstMatchingResult.SetTradeCount (20); MatchingResult SecondMatchingResult = new MatchingResult (); SecondMatchingResult.SetSuccess (false); // doreturn (x) .En (obj) .method () Após empilhar os métodos, depois de empilhar os métodos, o programa retornará o valor especificado conforme o esperado ao executar esses métodos. Os métodos que não são empilhados serão executados serão executados em tempo real. // Dois doreturnos significa que o FirstMatchingResult é devolvido quando o MatchingService.Matching é chamado primeiro, e o SecondMatchingResult é retornado quando a segunda chamada é chamada // porque há um loop enquanto o StartBuyProcess, o método de correspondência pode ser executado várias vezes MockitO.Doreturn (FirstMatchingSults). .Matching (Mockito.any (MatchingOrder.class), Mockito.any (Matchingorder.class)); MatchandOrder SellOrder = New Matchingorder (); SellOrder.setPrice (600); SellOrder.setCount (20); // pilhando o método gettopsEllorder Mockito.DORETURN (SellOrder) .When (MatchingService) .getTopsElder (Mockito.anystring ()); // empilhando o método externo que depende do Jedis Mockito.When (Jedisclient.Ircrby (Mockito.anystring (), Mockito.anylong ()). // startbuyprocess é a função em teste. Se você não acumular, MatchingService.StartBuyProcess (Buyorder, verdadeiro); // A afirmação subsequente de soma de verificação é testar o comportamento do método domatischingsuccess, que também é o objetivo deste teste.// Verificar pode ser usado para verificar quantas vezes um determinado método de classe foi executado? Aqui está para verificar se o JEDISCLIENT.ZREMFIRST foi executado uma vez que o Mockito.Verify (JEDISclient, Mockito.Times (1)). Zremfirst (Mockito.anystring ()); org.junit.assert.assertequals (3, Buyorder.getCount ()); org.junit.assert.assertequals (0, SellOrder.getCount ()); } O uso do espião foi demonstrado. Vamos falar sobre a "granularidade" dos testes de unidade do testStartBuyProcess_incaseofMatchingsuccess.
O objetivo de teststartbuyprocess_incaseofmatchingsuccess é testar domatedingsuccess. Trabalhamos muito para terminar os preparativos anteriores antes que possamos testar o domingsuckescess.
Uma prática melhor deve ser iniciar um novo método de teste para testar o domamento de resumo separadamente, e o foco também está concentrado. Depois que a Domatchingsuccess é substituída, o StartBuyProcess pode realmente cobrir seu próprio ramo de julgamento. A cobertura ainda é alcançada e o código de teste é mais fácil de manter. TestStartBuyProcess_incaseofMatchingSuccess é facilmente afetado por alterações devido a muitas responsabilidades consideradas. As pequenas coisas mudam pode afetar sua função normal.
Apresentando as dependências da estrutura de teste
<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> <cope> teste </cope> </pendes-> <pendence> <purbrouDId> org.springframework </frugiD> <TRAFACTID> Spring-test </stifactId> <versão 4.2.5.Release </sipers> <cope> teste </scope> </pendence>
Construção de contexto de trampolim+junit+mockito
Mockitobasedtest
@Runwith (springjunit4classrunner.class) @springApplicationConfiguration (classes = testApplication.class) public class. }} // Outras classes de teste herdam mockitobasedtest
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.