Write integration tests
This tutorial guides you through writing integration tests for your CorDapp. Integration tests allow you to test all features of your CorDapp together.
You will be creating your integration tests in this directory: workflows/src/test/java/com/tutorial/
Learning objectives
After you’ve completed this tutorial, you will be able to write integration tests for your CorDapp.
Before you start
Before you start writing your own unit tests:
- Read the API: Testing documentation.
- Download
TemplateInitiator.java
andTemplateContract.java
from the CorDapp tutorial repository. - Move
TemplateState.java
into yourcom.tutorial
package.
Write the CreateAndIssueAppleStamp
integration test
When writing flow unit tests, you rely on both states and contracts to test the functionality of the flow. You also must create a MockNetwork
with StartedMockNode
s. StartedMockNode
s behave like normal Corda nodes, but their services are mocked out.
Flow tests are generally more complicated, so R3 recommends having a file for each flow you wish to test.
Follow these steps to write a flow unit test for the CreateAndIssueAppleStampTest
:
Add the MockNetwork
and StartedMockNode
s
- Create a file called
CreateAndIssueAppleStampTest
. - Add the
CreateAndIssueAppleStampTest
public class. - Add the private
MockNetwork
and a network name. - Add two private
StartedMockNode
s nameda
andb
.
So far, your code should look like this:
package com.tutorial;
import net.corda.testing.node.MockNetwork;
import net.corda.testing.node.StartedMockNode;
public class CreateAndIssueAppleStampTest {
private MockNetwork network;
private StartedMockNode a;
private StartedMockNode b;
Add the CorDapp details
Next you must indicate where your CorDapp is so that the test engine can run:
- Add a
@Before
annotation to indicate that this is what must happen before the test is run. - Add a
public void setup
including thenew MockNetwork
andnew MockNetworkParameters
. UsewithCordappsForAllNodes
to reference the CorDapp. - Add the function
TestCorDapp.findCordapp
to find the contracts and flows JARs (com.tutorial.contracts
andcom.tutorial.flows
, respectively). - Create an
a
andb
node usingcreatePartyNode
. Usenull
for thelegalName
of the node to use the default. - Add the
runNetwork
command to start theMockNetwork
.
So far, your code should look like this:
package com.tutorial;
import com.google.common.collect.ImmutableList;
import net.corda.testing.node.MockNetwork;
import net.corda.testing.node.MockNetworkParameters;
import net.corda.testing.node.StartedMockNode;
import net.corda.testing.node.TestCordapp;
import org.junit.Before;
public class CreateAndIssueAppleStampTest {
private MockNetwork network;
private StartedMockNode a;
private StartedMockNode b;
@Before
public void setup() {
network = new MockNetwork(new MockNetworkParameters().withCordappsForAllNodes(ImmutableList.of(
TestCordapp.findCordapp("com.tutorial.contracts"),
TestCordapp.findCordapp("com.tutorial.flows"))));
a = network.createPartyNode(null);
b = network.createPartyNode(null);
network.runNetwork();
}
Add an @After
annotation and steps to tear down the network
After your test has run, you will want the network to be torn down to free up resources on your machine.
- Add an
@After
annotation. - Add a
tearDown
method. - Inside the method, add
stopNodes
command to stop the nodes on thenetwork
.
Add the test content
Now that you’ve added steps for before and after, you can finally add the content that will test your CreateAndIssueAppleStamp
flow.
- Add the
@Test
annotation. - Add a
public void
with theCreateAndIssueAppleStampTest
. - Reference the flow that is being tested to create the test flow. Here you should reference both the parent class of the flow (
CreateAndIssueAppleStamp
) and the initiating subflow (CreateAndIssueAppleStampInitiator
). Call thisflow1
in your test. - Add the
stampDescription
from your initiating flow with sample content - for example,stampDescription: "Honey Crisp 4072"
. - Reference the
b
node that you added in yourMockNetwork
usinggetInfo
,getLegalIdentities
, andget(0)
methods. This will return a party, completing the constructor. - You need a node to run the test flow you just created. Use node
a
and thestartFlow
command to startflow1
. - Add a
runNetwork
command to start the network and test the flow.
Add QueryCriteria
To verify that the flow test has run and the flow works, you must query the database of one of the StartedMockNode
s to see if the transaction was successfully stored. Since a
initiated the flow, you must check the database of node b
to ensure that the state was successfully issued to them.
- Create a query with
VaultQueryCriteria
. - In the
VaultQueryCriteria
, look for a status ofUNCONSUMED
using thewithStatus
method. - Add your query for the
AppleStamp
state. Use thegetServices
andgetVaultService
methods to query nodeb
’s vault. - Return a list of states with
getStates
, then return the reference of the first of these states withget(0)
. ReturngetState
to get the state, thengetData
to extract the data from the state. This gives you anAppleStamp
object. assert
thisAppleStamp
object to verify that thestampDesc
matches the example content you entered (Honey Crisp 4072
).
After you have finished writing the query, your flow test is finished and your code should look like this:
package com.tutorial;
import com.google.common.collect.ImmutableList;
import com.tutorial.flows.CreateAndIssueAppleStamp;
import com.tutorial.flows.TemplateInitiator;
import com.tutorial.states.AppleStamp;
import com.tutorial.states.TemplateState;
import net.corda.core.node.services.Vault;
import net.corda.core.node.services.vault.QueryCriteria;
import net.corda.core.transactions.SignedTransaction;
import net.corda.testing.node.MockNetwork;
import net.corda.testing.node.MockNetworkParameters;
import net.corda.testing.node.StartedMockNode;
import net.corda.testing.node.TestCordapp;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.concurrent.Future;
public class CreateAndIssueAppleStampTest {
private MockNetwork network;
private StartedMockNode a;
private StartedMockNode b;
@Before
public void setup() {
network = new MockNetwork(new MockNetworkParameters().withCordappsForAllNodes(ImmutableList.of(
TestCordapp.findCordapp("com.tutorial.contracts"),
TestCordapp.findCordapp("com.tutorial.flows"))));
a = network.createPartyNode(null);
b = network.createPartyNode(null);
network.runNetwork();
}
@After
public void tearDown() {
network.stopNodes();
}
@Test
public void dummyTest() {
TemplateInitiator flow = new TemplateInitiator(b.getInfo().getLegalIdentities().get(0));
Future<SignedTransaction> future = a.startFlow(flow);
network.runNetwork();
//successful query means the state is stored at node b's vault. Flow went through.
QueryCriteria inputCriteria = new QueryCriteria.VaultQueryCriteria().withStatus(Vault.StateStatus.UNCONSUMED);
TemplateState state = b.getServices().getVaultService()
.queryBy(TemplateState.class,inputCriteria).getStates().get(0).getState().getData();
}
@Test
public void CreateAndIssueAppleStampTest(){
CreateAndIssueAppleStamp.CreateAndIssueAppleStampInitiator flow1 =
new CreateAndIssueAppleStamp.CreateAndIssueAppleStampInitiator(
"HoneyCrispy 4072",this.b.getInfo().getLegalIdentities().get(0));
Future<SignedTransaction> future1 = a.startFlow(flow1);
network.runNetwork();
//successful query means the state is stored at node b's vault. Flow went through.
QueryCriteria inputCriteria = new QueryCriteria.VaultQueryCriteria()
.withStatus(Vault.StateStatus.UNCONSUMED);
AppleStamp state = b.getServices().getVaultService()
.queryBy(AppleStamp.class,inputCriteria).getStates().get(0).getState().getData();
assert(state.getStampDesc().equals("HoneyCrispy 4072"));
}
}
Take a look at the Apple Stamp CorDapp solution to see the implementation of integration tests for the RedeemApples
flow and the PackageApples
flow.
Was this page helpful?
Thanks for your feedback!
Chat with us
Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.
Propose documentation improvements directly
Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.
We're sorry this page wasn't helpful. Let us know how we can make it better!
Chat with us
Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.
Create an issue
Create a new GitHub issue in this repository - submit technical feedback, draw attention to a potential documentation bug, or share ideas for improvement and general feedback.
Propose documentation improvements directly
Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.