-
Notifications
You must be signed in to change notification settings - Fork 14
TestWithJava
** check out the Generated Java Code section **
Thanks to the cool project https://github.com/adridadou/eth-contract-api it is possible to test the contract code via junit on a private blockchain/ProxyBlockchain, which is very nice as no blockchain sync is needed and the tests are fast and reproducible.
The code generator can produce the necessary interfaces for the contract and the corresponding junit tests.
To get all working together you will need a defined project setup. A simple example project is here.
In addition to the basic software (see install) you need the maven plugin, as we will create a maven project which resolves all dependencies for us.
- maven plugin for eclipse
At first create a maven project | create a simple project without archetypes. | and set the group and the artifact id |
---|---|---|
You could now simply use the prepared archetype.
Now we need to add the dependencies for the project :
<dependencies>
<dependency>
<groupId>org.adridadou</groupId>
<artifactId>eth-contract-api</artifactId>
<version>0.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
And this is all it's needed. We need junit and the eth-contract-api. May be you need also the repository where maven finds the project.
<repository>
<id>bintray</id>
<url>https://dl.bintray.com/cubefriendly/maven/</url>
</repository>
Now add your model and we just need to configure the code generator. As the junit test will compile the solidity code the contract code need to be on the classpath. So you need to point the generation for the contract to a directory which is on the classpath.
So choose as generation directory for the contract code, for example, the src/test/resources
folder which is a nice place as it is on the classpath and also it is not a java code directory.
On the generate java page point the generation of the contract interfaces to a java folder, src/main/java
for example, as this is the place where the normal java code should go.
You could add a package prefix which is used as a suffix to the uml packages.
For the junit tests choose the src/test/java
folder as maven expect the junit tests there.
Define the type mapping, when a type is missing just add it.
The best way to map an address is currently String, and not org.adridadou.ethereum.EthAddress
as long as https://github.com/adridadou/eth-contract-api/issues/19 is open.
And you are ready to go.
For each contract a corresponding interface is created, when a function return more than one value the return value is stored in a generated dataholder named Return[operation.name.toUpperFirst()/][operation.operationReturnParameters()/]
. You will find more information in the wiki (https://github.com/adridadou/eth-contract-api/wiki/Complex-type-mapping). When a contract extends an other contract, the test will also extends the other contract test.
For each contract a junit test is created named [aClass.name/]Test
, it contains a test method for each public function in the contract. For each package a TestSuite called All[p.name.toUpperFirst()/]TestSuite
is created containing all tests of this package.
A test contains a setup of the blockchain, and the deployment of the contract.
/**
* Setup up the blockchain. Add the 'EthereumFacadeProvider' property to use
* another block chain implemenation or network.
*/
@BeforeClass
public static void setup() {
ECKey key = new ECKey();
sender = new EthAccount(key);
String property = System.getProperty("EthereumFacadeProvider");
EthereumFacadeProvider efp = new StandaloneEthereumFacadeProvider();
if(property!=null){
if (property.equalsIgnoreCase("main")) {
efp = new MainEthereumFacadeProvider();
}else if (property.equalsIgnoreCase("test")) {
efp = new TestnetEthereumFacadeProvider();
}else if (property.equalsIgnoreCase("morden")) {
efp = new MordenEthereumFacadeProvider();
}else if (property.equalsIgnoreCase("rcp")) {
RpcEthereumFacadeProvider rcp = new RpcEthereumFacadeProvider();
String url = System.getProperty("rcp-url");
ethereum = rcp.create(url);
return;//as this currently breaks the hierarchy
}
}
ethereum = efp.create();//new EthereumFacade(bcProxy);
}
You could change the used blockchain implementation via system property EthereumFacadeProvider
, adding via -D when starting the testing process for example. Currently these blockchains are supported :
- main - the main net
- morden - for the mordem test net
- test - for the testnet
- rcp - to connect to an running rcp instance
- url - this additional property defines the url of this instance
This might make sense in a continuous integration scenario.
The setup()
method simply creates the infrastructure, this is done only once per test. The method prepareTest()
loads the contract code from the classpath and the method createFixture()
will deploy the contact and set the fixture field.
The naming schema for the test are test[operation.name.toUpperFirst()/][operation.operationParameters()/]
.
For example testAddEntry_string_string()
. All the test functions contains protected code parts where you add your test code. The contract is available in the field fixture
.
/**
* Test method for addEntry.
* @throws Exception
*/
@Test
public void testAddEntry_string_string() throws Exception {
//Start of user code testAddEntry_string_string
assertEquals(0, fixture.count().intValue());
fixture.addEntry("aa","jj");
assertEquals(1, fixture.count().intValue());
fixture.addEntry("aa","jj");
assertEquals(2, fixture.count().intValue());
fixture.addEntry("aa","jj");
assertEquals(3, fixture.count().intValue());
//End of user code
}