How to mock a Java component within Mule Flow usin

2019-03-02 13:22发布

I am trying to Unit test one of my sub-flows using MUnit, I need to mock out a custom Java component but I am unable to do so.

My sub-flow reads as below

Subflow under test

<sub-flow name="ProcessCSVFlow" tracking:enable-default-events="true">
    <transformer ref="enrichWithHeaderAndEndOfFileTransformer" doc:name="headerAndEOFEnricher" />
    <set-variable variableName="outputfilename" value="#['Mercury'+server.dateTime.year+server.dateTime.month+server.dateTime.dayOfMonth+server.dateTime.hours +server.dateTime.minutes+server.dateTime.seconds+'.csv']" doc:name="outputfilename"/>
    <sftp:outbound-endpoint exchange-pattern="one-way" connector-ref="DestinationSFTP" host="${destination.host}" port="22" responseTimeout="10000" doc:name="DestinationSFTP"
    outputPattern="#[outputfilename]" path="${destination.path}" user="${destination.username}" password="${destination.password}"/>
    <!-- <component class="nz.co.mightyriver.creditreport.component.ArchiveOutputComponent" doc:name="Archive"/> -->
    <gzip-compress-transformer/>
    <sftp:outbound-endpoint exchange-pattern="one-way" connector-ref="InputSFTP" host="${source.host}" port="22" responseTimeout="10000" doc:name="SourceArchiveSFTP" 
    outputPattern="#[outputfilename].gzip" path="Archive" user="${source.username}" password="${source.password}"/>
    <component doc:name="Delete Read File">
        <singleton-object class="nz.co.mightyriver.creditreport.component.DeleteProcessedFileComponent">
            <property key="host" value="${source.host}"/>
            <property key="username" value="${source.username}"/>
            <property key="password" value="${source.password}"/>
            <property key="workingDirectory" value="${source.path}"/>
        </singleton-object>
    </component>
    <parse-template location="successmessagetemplate.txt" doc:name="Success Template"/>
    <smtp:outbound-endpoint host="${smtp.host}" port="${smtp.port}" user="${smtp.from.address}" password="${smtp.from.password}" 
                            to="${smtp.to.address}" from="${smtp.from.address}" subject="${mail.success.subject}" responseTimeout="10000" 
                            doc:name="SuccessEmail" connector-ref="Gmail"/>
    <logger message="Process completed successfully" level="INFO" doc:name="Logger"/>
</sub-flow>

This is my failing unit test

@Test
public void givenAValidPayload_whenFlowIsInvoked_itShouldSendPayloadToDestinationSFTPOnlyOnce() throws Exception {
    destinationSFTP.thenReturnSameEvent();
    sourceArchiveSFTP.thenReturnSameEvent();
    deleteProcessedFileComponent.thenReturnSameEvent();
    successEmail.thenReturnSameEvent();


    MuleEvent testEvent = PropertyEnricher.enrich(testEvent(IOUtils.toInputStream("hello,dummy,payload"))).get();

    runFlow(PROCESS_CSV_FLOW, testEvent);

    verifyCallOfMessageProcessor("outbound-endpoint")
            .ofNamespace("sftp")
            .withAttributes(attribute("name").ofNamespace("doc").withValue("DestinationSFTP"))
            .times(1);

}

My attempt at mocking out the component

deleteProcessedFileComponent = whenMessageProcessor("component")
            .withAttributes(attribute("name").ofNamespace("doc").withValue("Delete Read File"));

I have tried a few variations and none have worked, I am guessing a component is not a MessageProcessor

The exception I get is as follows

org.mule.api.lifecycle.InitialisationException: Component has not been initialized properly, no flow constuct.
at org.mule.component.AbstractComponent.initialise(AbstractComponent.java:218)
at org.mule.processor.chain.AbstractMessageProcessorChain.initialise(AbstractMessageProcessorChain.java:80)
at org.mule.processor.chain.AbstractMessageProcessorChain$$FastClassByCGLIB$$38c17d88.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.mule.munit.common.mp.WrapperMunitMessageProcessorInterceptor.invokeSuper(WrapperMunitMessageProcessorInterceptor.java:71)
at org.mule.munit.common.mp.WrapperMunitMessageProcessorInterceptor.invokeSuper(WrapperMunitMessageProcessorInterceptor.java:63)
at org.mule.munit.common.mp.WrapperMunitMessageProcessorInterceptor.intercept(WrapperMunitMessageProcessorInterceptor.java:49)
at org.mule.processor.chain.SubflowInterceptingChainLifecycleWrapper$$EnhancerByMUNIT$$c8ca2508.initialise(<generated>)
at org.mule.munit.runner.functional.FunctionalMunitSuite.initialiseSubFlow(FunctionalMunitSuite.java:269)
at org.mule.munit.runner.functional.FunctionalMunitSuite.runFlow(FunctionalMunitSuite.java:259)
at nz.co.mightyriver.ProcessCsvTest.givenAValidPayload_whenFlowIsInvoked_itShouldSendPayloadToDestinationSFTPOnlyOnce(ProcessCsvTest.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.run(ParentRunner.java:292)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

1条回答
Luminary・发光体
2楼-- · 2019-03-02 13:48

So there is no problem with your mock it actually work perfectly. The problem is with Mule and a little bit with MUnit.

Short answer, there is no fix for that right now. There is a workaround though!

Create a new xml (as to keep it separate from your production code) Add flow (not a sub-flow) to that new xml. In the flow you just added do a flow-ref to your sub-flow. From you test, instead of doing runFlow(PROCESS_CSV_FLOW), do runFlow("the_flow_you_created").

The longer answer is:

The sub-flows are not real flows, they don't even share a parent class. Thus they behave a little bit different. MUnit does some stuff to make that fact transparent to the user.

As it turns out we are not making enough, I'll create a jira in the MUnit project to tackle that issue. But hopefully you should be able to keep testing.

查看更多
登录 后发表回答