Mule ESB Teste: Teste integrado and (Endpoint)
Simulado com MUnit
Abstrato
ensaios, tal como geralmente reconhecido é uma parte importante do
processo de desenvolvimento de software. Os testes devem ser aplicadas
durante cada fase do processo de desenvolvimento de software de testes de
desenvolvedor para testes de aceitação. Em engenharia de software ternos
de teste abrangentes e automatizadas irá garantir a qualidade do software e
pode fornecer uma rede de segurança para alterações de regressão e de
incompatibilidade.
Em projetos de integração ESB Mule essas mesmas questões surgem.
Componentes usados nos fluxos de mula, os próprios fluxos e a integração
de fluxos em um contexto de sistema precisa ser testado.
Este artigo é o segundo de uma série de artigos sobre ensaio de projectos
Mule ESB em todos os níveis. Este artigo concentra-se em toda flui em um
projeto de mula que são testados por já combinando testado pequenos
componentes e sub fluxos em testes de integração.
MUNIT
MUNIT é um framework de testes da mula que foi criado originalmente
como um projeto paralelo em Mule, mas tornou-se open source mais tarde.
Ele suporta automatização de testes de aplicativos Mule para
desenvolvedores de mula. Ele é amplamente usado em várias empresas e
projetos internos mula [1].
Você pode encontrar o projeto no GitHub:
https://github.com/mulesoft/munit
Dependências
Vamos começar com as dependências do Maven necessários para MUNIT:
<dependency>
<groupId>org.mule.munit</groupId>
<artifactId>munit-common</artifactId>
<version>${munit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mule.munit</groupId>
<artifactId>munit-runner</artifactId>
<version>${munit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mule.munit.utils</groupId>
<artifactId>munit-mclient-module</artifactId>
<version>${munit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mule.munit</groupId>
<artifactId>munit-mock</artifactId>
<version>${munit.version}</version>
<scope>test</scope>
</dependency>
Definição de caso de teste - XML vs Java
Quando construímos testes de integração com MUNIT usamos
tecnicamente sua infra-estrutura de teste de unidade. Assim, temos testes
JUnit para executar testes de unidade para componentes e fluxos de sub e
testes de integração para fluxos inteiros. Estes testes de unidade pode ser
construído de duas maneiras com MUNIT. Ao utilizar uma descrição XML
que é chamado "código de mula" ou utilizando uma API fluente Java.
Nós apresentamos aqui o MUNIT Olá Mundo exemplo [2] [3]. Assumindo
que o seguinte fluxo deve ser testado. Observe que esta é uma sub fluxo
normal, pois não há entrada-endpoints presente:
<flow name="echoFlow" doc:name="echoFlow">
<echo-component/>
</flow>
“Mule code” testando um tal fluxo ficaria assim:
<!-- Load the config of MUnit -->
<munit:config/>
<!-- Load the definition of the flow under test -->
<spring:beans>
<spring:import resource="mule-config.xml"/>
</spring:beans>
<!-- Define the test case -->
<munit:test name="testingFlow"
description="We want to test that the flow always returns the same payload as we had
calling it.">
<!-- Define the input of the test case -->
<munit:set payload-ref="#[string: Hello world!]"/>
<!-- Call the flow under test -->
<flow-ref name="echoFlow"/>
<!-- Assert the test result -->
<munit:assert-not-null/>
<munit:assert-that payloadIs-ref="#[string: Hello world!]"/>
</munit:test>
O mesmo exemplo testado com a API fluente Mule Java requer um teste
JUnit que é derivado de FunctionalMunitSuite e ficaria assim:
public class FirstTest extends FunctionalMunitSuite {
/**
* This can be omitted. In that case, the config resources will be taken from mule-deploy
properties file.
* @return The location of your MULE config file.
*/
@Override
protected String getConfigResources() {
return "mule-config.xml";
}
@Test
public void testEchoFlow() throws Exception {
// Start the flow "echoFlow" with Mule event from testEvent(...) with the payload "Hello w
orld!"
MuleEvent resultEvent = runFlow("echoFlow", testEvent("Hello world!"));
// Get the payload result from the flow and assert the result
assertEquals("Hello world!", resultEvent.getMessage().getPayloadAsString());
}
}
Por favor notar a sobrescrita do protected String
getConfigResources()método que fornece uma vírgula lista de mula e
arquivos XML Primavera separadas para o teste. Ele deve conter definições
de fluxo de produção e configurações de teste para separar a produção e
teste.
Quando se trata da comparação de ambas as abordagens pode-se
argumentar que é uma questão de sabor. Isso pode ser verdade para os
fluxos simples e casos de teste. Especialmente quando se utiliza verificação
ou espionagem (veja abaixo), pode-se argumentar que o uso de XML é
melhor legível. No entanto, quando temos uma grande base de teste com
vários casos de teste e muitos fluxos de sub, a reutilização de código de
teste se torna um problema. Por isso, preferem a abordagem Java sobre a
abordagem XML porque permite mais fácil a reutilização de classes
auxiliares, arquivos de configuração de teste e classes de teste pai.
Portanto, vamos ficar agora com exemplos de Java, mas estar cientes de
que há sempre uma alternativa de estilo XML também.
Executando um fluxo síncrono
Tal como representado na última exemplo este fluxo simples foi iniciado
usando o protected final MuleEvent runFlow(String name, MuleEvent
event) throws MuleException método da classe FunctionalMunitSuite. O
importante é lembrar que mesmo um fluxo que tem um ponto de
extremidade de entrada, através da qual ele é iniciado pode ser iniciado
desta forma, também.
Vamos assumir que temos um serviço a preços que integra três
fornecedores para um atacadista. Ele solicita uma cotação de preço através
dos serviços e recebe três resultados. A integração destas três fornecedores
poderia ser assim:
<jms:inbound-endpoint exchange-pattern="request-response" queue="QuoteQueue" doc
<scatter-gather doc:name="Scatter-Gather">
<!-- JMS call -->
<jms:outbound-endpoint exchange-pattern="request-response" queue="Supplier1Queue
<!-- SOAP call -->
<processor-chain>
<cxf:jaxws-client serviceClass="de.codecentric.example.PricingInterface" operation="g
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port=
<object-to-string-transformer doc:name="Object to String"/>
</processor-chain>
<!-- REST call -->
<processor-chain>
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port=
GET" doc:name="HTTP"/>
<object-to-string-transformer doc:name="Object to String"/>
</processor-chain>
</scatter-gather>
<notification:send-business-notification config-ref="NotificationConfig" message="Gat
name="Business Notification"/>
Para executar esse fluxo o protected final MuleEvent runFlow(String name,
MuleEvent event) throws MuleException método precisa de ser fornecida
com um MuleEvent. Isto pode ser feito usando o método de
conveniência protected final MuleEvent testEvent(Object payload) throws
Exception o que cria um evento de mula ou criando ela própria. Quanto
mais tarde fornece controle adicional para o caso de teste porque a
mensagem Mule pode ser adaptado de forma explícita, por exemplo,
definindo as propriedades de mula:
@Test
public void testPricingFlow() {
// Create MuleMessage with a String payload
MuleMessage mockedInboundMsg = muleMessageWithPayload("PROD123");
// Additional properties for the message can be set
mockedInboundMsg.setInvocationProperty("aProperty", "aValue");
// Create a MuleEvent
MuleEvent mockedEvent = new DefaultMuleEvent(mockedInboundMsg, MessageExcha
, MuleTestUtils.getTestFlow(muleContext));
// Run the flow and receive the result of the flow
MuleEvent flowResult = runFlow("testFlow", mockedEvent);
...
Simulando
Quando se trata de colocar todos os componentes testados e fluxos de sub
juntos a tarefa de testar a sua integração se torna mais e mais complicada.
Especialmente quando outros sistemas externos que não podem ser
simuladas são usados nestes fluxos. Para a integração de ensaio de uma das
maiores características do quadro MUNIT é a capacidade de todos os
processadores no zombando um fluxo de mula [4]. Isso permite que um
teste completo do fluxo geral.
Para testar esse fluxo e a transformação circundante, encaminhamento e
outra lógica do endpoint de entrada e três chamadas de saída pode ser
ridicularizado desta forma antes do teste é executado e afirmou:
@Test
public void testPricingFlow() {
...
// Mock the inbound processors to return a mocked input for the flow
whenMessageProcessor("inbound-endpoint")
.ofNamespace("http")
.thenReturn(mockedInboundMsg).getMessage());
// Mock the outbound processors to return a mocked result
whenMessageProcessor("outbound-endpoint")
.ofNamespace("jms")
.thenReturn(muleMessageWithPayload("90 EUR").getMessage());
whenMessageProcessor("outbound-endpoint")
.ofNamespace("http")
// Filter by message processor attributes of the endpoint
.withAttributes(attribute("host").withValue("100.55.32.*"))
.thenReturn(muleMessageWithPayload("100 EUR").getMessage());
whenMessageProcessor("outbound-endpoint")
.ofNamespace("http")
// Filter by message processor attributes of the endpoint
.withAttributes(attribute("host").withValue(Matcher.contains("200.23.10
0.190")))
.thenReturn(muleMessageWithPayload("110 EUR").getMessage());
// Mock a flow processors to return a the same event
whenMessageProcessor("send-business-notification")
.ofNamespace("notification")
.thenReturnSameEvent();
...
}
Desta forma, você tem total controle sobre o fluxo. Nós temos a mensagem
de entrada escarnecido, que é devolvido para simular o ponto de
extremidade de entrada e as mensagens de saída zombaram retornou que
simulam as chamadas externas.
Para esse efeito, o FunctionalMunitSuite classe fornece o método
whenMessageProcessor(String nameOfMessageProcessor) que retorna uma
instância de MessageProcessorMocker simulado de um processador
específico. O processador zombou pode ainda ser especificado pelo
encadeamento de atributos com o método public MessageProcessorMocker
withAttributes(Attribute ... attributes). The public Attribute
withValue(Object value) método pode ser usado com a classe Matchers ou
qualquer dos métodos auxiliares da classe FunctionalMunitSuite e fornecer
uma variedade de controle sobre o zombeteiro. Além disso, mesmo
manipulação de exceção no fluxo pode ser testada com o public void
thenThrow(Throwable exception) metodos.
Afirmando, verificação e espionagem
Para um teste completo do comportamento interior dos fluxos afirma de
mensagens, verificação de chamadas de processador e espionagem em
processadores podem ser usados [5] [6].
Basicamente mensagens pode ser afirmado em Mule a maneira clássica de
Java com JUnit afirma. Isto pode ser melhorado utilizando uma API
matchers tais como Hamcrest AssertJ ou que fornece um matchers API
fluente. Nós preferimos o uso de AssertJ por causa da nossa preferência dos
fluente API.
Para fins de teste MUNIT fornece uma ótima maneira de verificar o
comportamento de um fluxo. Ele fornece uma estrutura de verificação que
permite inspecionar as chamadas processador após um teste. Quando você
tem o exemplo acima e deseja verificar se todos os terminais de saída
foram chamados você poderia fazer isso no final de um teste através dos
seguintes métodos de verificação que também afirmam se a verificação
falhar:
@Test
public void testPricingFlow() {
...
// Verify JMS outbound endpoint was called one time
verifyCallOfMessageProcessor("outbound-endpoint").ofNamespace("jms").ti
mes(1);
// Verify HTTP outbound endpoint for supplier 1 was called one time
verifyCallOfMessageProcessor("outbound-endpoint").ofNamespace("http")
.withAttributes(attribute("host").withValue("100.55.32.125")).times(1);
// Verify HTTP outbound endpoint for supplier 2 was called one time
verifyCallOfMessageProcessor("outbound-endpoint").ofNamespace("http")
.withAttributes(attribute("host").withValue("200.23.100.190")).times(1);
...
}
Novamente usando a classe FunctionalMunitSuite que tem para o efeito o
método verifyCallOfMessageProcessor(String
nameOfMessageProcessor) o que cria uma instância de MunitVerifier a
definição da verificação é feita. o Attribute withValue(Object
value) método em combinação com public MunitVerifier
withAttributes(Attribute ... attributes) método pode ser utilizado para
adaptar a verificação da mesma forma que com os processadores
simulados.
Como uma alternativa para afirma no final da espionagem fluxo pode ser
usado para ligar e incluem código afirmar durante a execução do fluxo.
Vamos supor que queremos verificar se a entrada e saída para os
processadores de saída está em um formato válido:
@Test
public void testPricingFlow() {
...
// Spy on the input and output of the processor
spyMessageProcessor("outbound-endpoint").ofNamespace("jms")
.before(new BeforeSpy())
.after(new AfterSpy());
// Spy on the input and output of the processor
spyMessageProcessor("outbound-endpoint").ofNamespace("http")
.withAttributes(attribute("host").withValue("100.55.32.125"))
.before(new BeforeSpy())
.after(new AfterSpy());
// Spy on the input and output of the processor
spyMessageProcessor("outbound-endpoint").ofNamespace("http")
.withAttributes(attribute("host").withValue("200.23.100.190"))
.before(new BeforeSpy())
.after(new AfterSpy());
...
}
private class BeforeSpy implements SpyProcess
{
@Override
public void spy(MuleEvent event) throws MuleException
{
// Assert that the payload is a product code which is of type String and starts
with PROD
assertThat(event.getMessage().getPayload()).isOfAnyClassIn(String.class);
assertThat(event.getMessage().getPayloadAsString()).startsWith("PROD");
}
}
private class AfterSpy implements SpyProcess
{
@Override
public void spy(MuleEvent event) throws MuleException
{
// Assert that the resulting payload is of type String and is a digit
assertThat(event.getMessage().getPayload()).isOfAnyClassIn(String.class);
assertThat(event.getMessage().getPayloadAsString()).matches("^d+$");
}
}
Tal como acontece com zombando e verificação vemos aqui o mesmo
padrão que permite a definição do processador de espionagem. A classe
FunctionalMunitSuite tem a spyMessageProcessor método (String nome),
que fornece uma instância de MunitSpy para a definição do processador de
espionagem. Mais uma vez, pode ser reduzida usando atributos. Usando os
métodos antes (SpyProcess última ... withSpy) e depois (SpyProcess última
... withSpy) instâncias de uma classe filho de SpyProcess pode ser
adicionado a serem executados antes e depois de mensagens passa um
processador de mensagens durante um test-run.
Executando um fluxo assíncrono ou sondados
Para os testes assíncrona flui essa dependência adicional é necessário:
<dependency>
<groupId>org.mule.modules</groupId>
<artifactId>munit-synchronize-module</artifactId>
<version>3.5-M1</version>
<scope>test</scope>
</dependency>
Ele fornece a classe sincronizador que contém uma infra-estrutura de
tempo limite. O método process(MuleEvent event) throws
Exception precisa ser substituído com uma chamada para o fluxo
assíncrono:
@Test
public void testPricingFlow() {
...
Synchronizer synchronizer = new Synchronizer(muleContext, 20000l) {
@Override
protected MuleEvent process(MuleEvent event) throws Exception {
runFlow("asyncPricingFlow", event);
return null;
}
};
MuleEvent event = new DefaultMuleEvent(muleMessageWithPayload("PROD123"), Me
MuleTestUtils.getTestFlow(muleContext));
synchronizer.runAndWait(event);
...
}
Para afirmar o comportamento da espionagem do quadro MUNIT vem a
calhar. Basta pendurar uma classe de espionagem após a última
processador ou em outro local lógico para verificar o resultado do fluxo.
Para os ensaios sobre polling flui o caso de teste precisa antes desativar
polling idealmente quando o contexto Mule foi criado:
@Override
protected void muleContextCreated(MuleContext muleContext) {
MunitPollManager.instance(muleContext).avoidPollLaunch();
}
Depois, os dados de ensaio podem ser criados, por exemplo, um banco de
dados em memória pode ser preenchida que é monitorado pelo fluxo. Em
seguida, a votação pode ser desencadeada na classe sincronizador depois:
@Override
protected MuleEvent process(MuleEvent event) throws Exception {
MunitPollManager.instance(muleContext).schedulePoll("polledFlow");
return event;
}
Novamente a funcionalidade Spy pode ser utilizado para verificar o
comportamento do fluxo. Afirmar que o resultado de um fluxo assíncrono
ou entrevistados está correto um assert clássico é realizada após a
conclusão. No nosso exemplo, o banco de dados de teste pode ser
consultado e o resultado do teste pode ser verificada.
Conclusão
Nós mostramos neste artigo como testes de integrações de aplicações multi
módulo mula pode ser realizada. Usando casos de teste simples MUNIT
podem ser construídos usando uma descrição XML ou código Java em si.
Processadores como saída e terminais de entrada podem ser ridicularizado
em tais testes e os fluxos, portanto, integrados podem ser exaustivamente
testado. Usando afirma, verificação e espionar o comportamento correto de
um fluxo pode ser inspecionados e testados, sem tocar o código de
produção ou fluxo definição. Além disso, nós descreveu as alterações
adicionais aos fluxos assíncronos e consultados.

Mule esb teste parte 2

  • 1.
    Mule ESB Teste:Teste integrado and (Endpoint) Simulado com MUnit Abstrato ensaios, tal como geralmente reconhecido é uma parte importante do processo de desenvolvimento de software. Os testes devem ser aplicadas durante cada fase do processo de desenvolvimento de software de testes de desenvolvedor para testes de aceitação. Em engenharia de software ternos de teste abrangentes e automatizadas irá garantir a qualidade do software e pode fornecer uma rede de segurança para alterações de regressão e de incompatibilidade. Em projetos de integração ESB Mule essas mesmas questões surgem. Componentes usados nos fluxos de mula, os próprios fluxos e a integração de fluxos em um contexto de sistema precisa ser testado. Este artigo é o segundo de uma série de artigos sobre ensaio de projectos Mule ESB em todos os níveis. Este artigo concentra-se em toda flui em um projeto de mula que são testados por já combinando testado pequenos componentes e sub fluxos em testes de integração. MUNIT MUNIT é um framework de testes da mula que foi criado originalmente como um projeto paralelo em Mule, mas tornou-se open source mais tarde. Ele suporta automatização de testes de aplicativos Mule para desenvolvedores de mula. Ele é amplamente usado em várias empresas e projetos internos mula [1].
  • 2.
    Você pode encontraro projeto no GitHub: https://github.com/mulesoft/munit Dependências Vamos começar com as dependências do Maven necessários para MUNIT: <dependency> <groupId>org.mule.munit</groupId> <artifactId>munit-common</artifactId> <version>${munit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mule.munit</groupId> <artifactId>munit-runner</artifactId> <version>${munit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mule.munit.utils</groupId> <artifactId>munit-mclient-module</artifactId> <version>${munit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mule.munit</groupId> <artifactId>munit-mock</artifactId> <version>${munit.version}</version> <scope>test</scope> </dependency> Definição de caso de teste - XML vs Java Quando construímos testes de integração com MUNIT usamos tecnicamente sua infra-estrutura de teste de unidade. Assim, temos testes JUnit para executar testes de unidade para componentes e fluxos de sub e testes de integração para fluxos inteiros. Estes testes de unidade pode ser
  • 3.
    construído de duasmaneiras com MUNIT. Ao utilizar uma descrição XML que é chamado "código de mula" ou utilizando uma API fluente Java. Nós apresentamos aqui o MUNIT Olá Mundo exemplo [2] [3]. Assumindo que o seguinte fluxo deve ser testado. Observe que esta é uma sub fluxo normal, pois não há entrada-endpoints presente: <flow name="echoFlow" doc:name="echoFlow"> <echo-component/> </flow> “Mule code” testando um tal fluxo ficaria assim: <!-- Load the config of MUnit --> <munit:config/> <!-- Load the definition of the flow under test --> <spring:beans> <spring:import resource="mule-config.xml"/> </spring:beans> <!-- Define the test case --> <munit:test name="testingFlow" description="We want to test that the flow always returns the same payload as we had calling it."> <!-- Define the input of the test case --> <munit:set payload-ref="#[string: Hello world!]"/> <!-- Call the flow under test --> <flow-ref name="echoFlow"/> <!-- Assert the test result --> <munit:assert-not-null/> <munit:assert-that payloadIs-ref="#[string: Hello world!]"/> </munit:test> O mesmo exemplo testado com a API fluente Mule Java requer um teste JUnit que é derivado de FunctionalMunitSuite e ficaria assim:
  • 4.
    public class FirstTestextends FunctionalMunitSuite { /** * This can be omitted. In that case, the config resources will be taken from mule-deploy properties file. * @return The location of your MULE config file. */ @Override protected String getConfigResources() { return "mule-config.xml"; } @Test public void testEchoFlow() throws Exception { // Start the flow "echoFlow" with Mule event from testEvent(...) with the payload "Hello w orld!" MuleEvent resultEvent = runFlow("echoFlow", testEvent("Hello world!")); // Get the payload result from the flow and assert the result assertEquals("Hello world!", resultEvent.getMessage().getPayloadAsString()); } } Por favor notar a sobrescrita do protected String getConfigResources()método que fornece uma vírgula lista de mula e arquivos XML Primavera separadas para o teste. Ele deve conter definições de fluxo de produção e configurações de teste para separar a produção e teste. Quando se trata da comparação de ambas as abordagens pode-se argumentar que é uma questão de sabor. Isso pode ser verdade para os fluxos simples e casos de teste. Especialmente quando se utiliza verificação ou espionagem (veja abaixo), pode-se argumentar que o uso de XML é melhor legível. No entanto, quando temos uma grande base de teste com vários casos de teste e muitos fluxos de sub, a reutilização de código de teste se torna um problema. Por isso, preferem a abordagem Java sobre a abordagem XML porque permite mais fácil a reutilização de classes auxiliares, arquivos de configuração de teste e classes de teste pai.
  • 5.
    Portanto, vamos ficaragora com exemplos de Java, mas estar cientes de que há sempre uma alternativa de estilo XML também. Executando um fluxo síncrono Tal como representado na última exemplo este fluxo simples foi iniciado usando o protected final MuleEvent runFlow(String name, MuleEvent event) throws MuleException método da classe FunctionalMunitSuite. O importante é lembrar que mesmo um fluxo que tem um ponto de extremidade de entrada, através da qual ele é iniciado pode ser iniciado desta forma, também. Vamos assumir que temos um serviço a preços que integra três fornecedores para um atacadista. Ele solicita uma cotação de preço através dos serviços e recebe três resultados. A integração destas três fornecedores poderia ser assim: <jms:inbound-endpoint exchange-pattern="request-response" queue="QuoteQueue" doc <scatter-gather doc:name="Scatter-Gather"> <!-- JMS call --> <jms:outbound-endpoint exchange-pattern="request-response" queue="Supplier1Queue <!-- SOAP call --> <processor-chain> <cxf:jaxws-client serviceClass="de.codecentric.example.PricingInterface" operation="g <http:outbound-endpoint exchange-pattern="request-response" host="localhost" port= <object-to-string-transformer doc:name="Object to String"/> </processor-chain> <!-- REST call --> <processor-chain> <http:outbound-endpoint exchange-pattern="request-response" host="localhost" port= GET" doc:name="HTTP"/> <object-to-string-transformer doc:name="Object to String"/> </processor-chain> </scatter-gather> <notification:send-business-notification config-ref="NotificationConfig" message="Gat name="Business Notification"/>
  • 6.
    Para executar essefluxo o protected final MuleEvent runFlow(String name, MuleEvent event) throws MuleException método precisa de ser fornecida com um MuleEvent. Isto pode ser feito usando o método de conveniência protected final MuleEvent testEvent(Object payload) throws Exception o que cria um evento de mula ou criando ela própria. Quanto mais tarde fornece controle adicional para o caso de teste porque a mensagem Mule pode ser adaptado de forma explícita, por exemplo, definindo as propriedades de mula: @Test public void testPricingFlow() { // Create MuleMessage with a String payload MuleMessage mockedInboundMsg = muleMessageWithPayload("PROD123"); // Additional properties for the message can be set mockedInboundMsg.setInvocationProperty("aProperty", "aValue"); // Create a MuleEvent MuleEvent mockedEvent = new DefaultMuleEvent(mockedInboundMsg, MessageExcha , MuleTestUtils.getTestFlow(muleContext)); // Run the flow and receive the result of the flow MuleEvent flowResult = runFlow("testFlow", mockedEvent); ... Simulando Quando se trata de colocar todos os componentes testados e fluxos de sub juntos a tarefa de testar a sua integração se torna mais e mais complicada. Especialmente quando outros sistemas externos que não podem ser simuladas são usados nestes fluxos. Para a integração de ensaio de uma das maiores características do quadro MUNIT é a capacidade de todos os processadores no zombando um fluxo de mula [4]. Isso permite que um teste completo do fluxo geral. Para testar esse fluxo e a transformação circundante, encaminhamento e outra lógica do endpoint de entrada e três chamadas de saída pode ser ridicularizado desta forma antes do teste é executado e afirmou:
  • 7.
    @Test public void testPricingFlow(){ ... // Mock the inbound processors to return a mocked input for the flow whenMessageProcessor("inbound-endpoint") .ofNamespace("http") .thenReturn(mockedInboundMsg).getMessage()); // Mock the outbound processors to return a mocked result whenMessageProcessor("outbound-endpoint") .ofNamespace("jms") .thenReturn(muleMessageWithPayload("90 EUR").getMessage()); whenMessageProcessor("outbound-endpoint") .ofNamespace("http") // Filter by message processor attributes of the endpoint .withAttributes(attribute("host").withValue("100.55.32.*")) .thenReturn(muleMessageWithPayload("100 EUR").getMessage()); whenMessageProcessor("outbound-endpoint") .ofNamespace("http") // Filter by message processor attributes of the endpoint .withAttributes(attribute("host").withValue(Matcher.contains("200.23.10 0.190"))) .thenReturn(muleMessageWithPayload("110 EUR").getMessage()); // Mock a flow processors to return a the same event whenMessageProcessor("send-business-notification") .ofNamespace("notification") .thenReturnSameEvent(); ... } Desta forma, você tem total controle sobre o fluxo. Nós temos a mensagem de entrada escarnecido, que é devolvido para simular o ponto de extremidade de entrada e as mensagens de saída zombaram retornou que simulam as chamadas externas. Para esse efeito, o FunctionalMunitSuite classe fornece o método whenMessageProcessor(String nameOfMessageProcessor) que retorna uma
  • 8.
    instância de MessageProcessorMockersimulado de um processador específico. O processador zombou pode ainda ser especificado pelo encadeamento de atributos com o método public MessageProcessorMocker withAttributes(Attribute ... attributes). The public Attribute withValue(Object value) método pode ser usado com a classe Matchers ou qualquer dos métodos auxiliares da classe FunctionalMunitSuite e fornecer uma variedade de controle sobre o zombeteiro. Além disso, mesmo manipulação de exceção no fluxo pode ser testada com o public void thenThrow(Throwable exception) metodos. Afirmando, verificação e espionagem Para um teste completo do comportamento interior dos fluxos afirma de mensagens, verificação de chamadas de processador e espionagem em processadores podem ser usados [5] [6]. Basicamente mensagens pode ser afirmado em Mule a maneira clássica de Java com JUnit afirma. Isto pode ser melhorado utilizando uma API matchers tais como Hamcrest AssertJ ou que fornece um matchers API fluente. Nós preferimos o uso de AssertJ por causa da nossa preferência dos fluente API. Para fins de teste MUNIT fornece uma ótima maneira de verificar o comportamento de um fluxo. Ele fornece uma estrutura de verificação que permite inspecionar as chamadas processador após um teste. Quando você tem o exemplo acima e deseja verificar se todos os terminais de saída foram chamados você poderia fazer isso no final de um teste através dos seguintes métodos de verificação que também afirmam se a verificação falhar: @Test
  • 9.
    public void testPricingFlow(){ ... // Verify JMS outbound endpoint was called one time verifyCallOfMessageProcessor("outbound-endpoint").ofNamespace("jms").ti mes(1); // Verify HTTP outbound endpoint for supplier 1 was called one time verifyCallOfMessageProcessor("outbound-endpoint").ofNamespace("http") .withAttributes(attribute("host").withValue("100.55.32.125")).times(1); // Verify HTTP outbound endpoint for supplier 2 was called one time verifyCallOfMessageProcessor("outbound-endpoint").ofNamespace("http") .withAttributes(attribute("host").withValue("200.23.100.190")).times(1); ... } Novamente usando a classe FunctionalMunitSuite que tem para o efeito o método verifyCallOfMessageProcessor(String nameOfMessageProcessor) o que cria uma instância de MunitVerifier a definição da verificação é feita. o Attribute withValue(Object value) método em combinação com public MunitVerifier withAttributes(Attribute ... attributes) método pode ser utilizado para adaptar a verificação da mesma forma que com os processadores simulados. Como uma alternativa para afirma no final da espionagem fluxo pode ser usado para ligar e incluem código afirmar durante a execução do fluxo. Vamos supor que queremos verificar se a entrada e saída para os processadores de saída está em um formato válido: @Test public void testPricingFlow() { ... // Spy on the input and output of the processor spyMessageProcessor("outbound-endpoint").ofNamespace("jms") .before(new BeforeSpy()) .after(new AfterSpy());
  • 10.
    // Spy onthe input and output of the processor spyMessageProcessor("outbound-endpoint").ofNamespace("http") .withAttributes(attribute("host").withValue("100.55.32.125")) .before(new BeforeSpy()) .after(new AfterSpy()); // Spy on the input and output of the processor spyMessageProcessor("outbound-endpoint").ofNamespace("http") .withAttributes(attribute("host").withValue("200.23.100.190")) .before(new BeforeSpy()) .after(new AfterSpy()); ... } private class BeforeSpy implements SpyProcess { @Override public void spy(MuleEvent event) throws MuleException { // Assert that the payload is a product code which is of type String and starts with PROD assertThat(event.getMessage().getPayload()).isOfAnyClassIn(String.class); assertThat(event.getMessage().getPayloadAsString()).startsWith("PROD"); } } private class AfterSpy implements SpyProcess { @Override public void spy(MuleEvent event) throws MuleException { // Assert that the resulting payload is of type String and is a digit assertThat(event.getMessage().getPayload()).isOfAnyClassIn(String.class); assertThat(event.getMessage().getPayloadAsString()).matches("^d+$"); } } Tal como acontece com zombando e verificação vemos aqui o mesmo padrão que permite a definição do processador de espionagem. A classe FunctionalMunitSuite tem a spyMessageProcessor método (String nome), que fornece uma instância de MunitSpy para a definição do processador de
  • 11.
    espionagem. Mais umavez, pode ser reduzida usando atributos. Usando os métodos antes (SpyProcess última ... withSpy) e depois (SpyProcess última ... withSpy) instâncias de uma classe filho de SpyProcess pode ser adicionado a serem executados antes e depois de mensagens passa um processador de mensagens durante um test-run. Executando um fluxo assíncrono ou sondados Para os testes assíncrona flui essa dependência adicional é necessário: <dependency> <groupId>org.mule.modules</groupId> <artifactId>munit-synchronize-module</artifactId> <version>3.5-M1</version> <scope>test</scope> </dependency> Ele fornece a classe sincronizador que contém uma infra-estrutura de tempo limite. O método process(MuleEvent event) throws Exception precisa ser substituído com uma chamada para o fluxo assíncrono: @Test public void testPricingFlow() { ... Synchronizer synchronizer = new Synchronizer(muleContext, 20000l) { @Override protected MuleEvent process(MuleEvent event) throws Exception { runFlow("asyncPricingFlow", event); return null; } }; MuleEvent event = new DefaultMuleEvent(muleMessageWithPayload("PROD123"), Me MuleTestUtils.getTestFlow(muleContext)); synchronizer.runAndWait(event);
  • 12.
    ... } Para afirmar ocomportamento da espionagem do quadro MUNIT vem a calhar. Basta pendurar uma classe de espionagem após a última processador ou em outro local lógico para verificar o resultado do fluxo. Para os ensaios sobre polling flui o caso de teste precisa antes desativar polling idealmente quando o contexto Mule foi criado: @Override protected void muleContextCreated(MuleContext muleContext) { MunitPollManager.instance(muleContext).avoidPollLaunch(); } Depois, os dados de ensaio podem ser criados, por exemplo, um banco de dados em memória pode ser preenchida que é monitorado pelo fluxo. Em seguida, a votação pode ser desencadeada na classe sincronizador depois: @Override protected MuleEvent process(MuleEvent event) throws Exception { MunitPollManager.instance(muleContext).schedulePoll("polledFlow"); return event; } Novamente a funcionalidade Spy pode ser utilizado para verificar o comportamento do fluxo. Afirmar que o resultado de um fluxo assíncrono ou entrevistados está correto um assert clássico é realizada após a conclusão. No nosso exemplo, o banco de dados de teste pode ser consultado e o resultado do teste pode ser verificada. Conclusão Nós mostramos neste artigo como testes de integrações de aplicações multi módulo mula pode ser realizada. Usando casos de teste simples MUNIT podem ser construídos usando uma descrição XML ou código Java em si. Processadores como saída e terminais de entrada podem ser ridicularizado em tais testes e os fluxos, portanto, integrados podem ser exaustivamente testado. Usando afirma, verificação e espionar o comportamento correto de
  • 13.
    um fluxo podeser inspecionados e testados, sem tocar o código de produção ou fluxo definição. Além disso, nós descreveu as alterações adicionais aos fluxos assíncronos e consultados.