Jonas Snellinckx
Mar 14, 2018 · 4 min read

⚠️ Note: Since writing this article, our module has gone through some changes and updates. Please check the github for the latest info.

This article is a second part of our “how to Hyperledger Fabric nodejs chaincode” articles. Last article was about developing the chaincode, which we wrote a package for. It makes writing chaincode much faster.

There wasn’t any good solution for testing nodejs chaincode yet. This is why we created the mockstub package. To be honest, I don’t like testing either. But since upgrading chaincode isn’t the quickest thing in the world, there’s a lot of time to be saved testing. Also, more importantly, since Blockchain is immutable and supposed to be secure because the code is on the network, we rather not leave flaws in our code.


Testing using our mockstub

This ChaincodeMockStub is a mock implementation of the fabric-shim stub. This means you can test your chaincode without actually starting your network. It implements almost every function the actual stub does, but in memory. Only these functions are not (yet) supported: getHistoryForKey , getBinding , getTransient , setEvent , getChannelID .

How to test

yarn add @theledger/fabric-mock-stub --dev

Testing Nodejs chaincode works similarly to testing using the mockstub in the Golang chaincode. The ChaincodeMockStub has 2 important mock functions mockInitand mockInvoke. By passing your chaincode, it will mock a transaction and execute an invoke/init similarly to how it originally will be called.

Response

Both these functions will return a ChaincodeResponse. Using this ChaincodeResponse object, we can test whether or not the action returned an expected result.

On success, the response will look like this. It always return a status and if the method returns something, the response will also contain a payload.

{
"status": 200,
"payload": <Buffer_with_your_data>
}

On error, the response will look like this. The payload will be replaced by a message field containing the error.

{
"status": 500,
"message": <Buffer_with_your_error_message>
}

You’ll be able to validate the response using something like chai. The Transform used here is a helper which is shipped with the mockstub to easily serialize and deserialize data.

Example how to expect results

Include your chaincode

At the top of your test file, you can import and instantiate your chaincode, this only has to be done once. Make sure you seperate the shim.start() from your chaincode. Otherwise it will be executed before testing and errors will occur. An example can be found in our network boilerplate.

import chaincode

Include the mockstub

After this, in your tests, you can create a new mockstub. You have to pass a random name (not important at the moment) and your chaincode.

It’s up to you if you want to create a new mockstub for each test, or have one shared for all tests. Sharing one for all the tests will keep your previous state in memory. If you don’t want this, create a new one for each test. Keep this in mind.

import mockstub

Example

A test would look like this. Now we just need some testing logic.

Test Init

The Init()method can be tested using the mockStub.mockInit(txId: string, args: string[]) function. It will create a new mock transaction and call the init method on your chaincode. Since the init happens when instantiating your chaincode, you generally don't want it to return anything. So we check the response status here.

Test for Init()

Test Invoke

The Invoke()method can be tested using the mockStub.mockInvoke(txId: string, args: string[]) function. It will create a new mock transaction and call the invoke method on your chaincode. The client will either send a query or an invoke, but the chaincode will accept these both as invoke. In your tests there isn't any difference, both invokes and queries can return a result.

Test queryCar

Test Invoke queryCar

Test createCar

Test Invoke createCar

TheLedger — Blockchain experts/consultants in Belgium & The Netherlands.

Testing individual classes

You are not required to only test using the mockInvoke and mockInit. You can directly call the methods on your chaincode or on the mockStub if you really want to.

Testing using Mychaincode directly

A remark when using this, depending what you return in your function, you will be able to receive a Buffer or an object in your tests. This is discussed at the top of this blog post.

Test queryCar on chaincode directly

Conclusion

I hear you, I hate writing tests aswell. But I think the fabric-shim really needed this. I would like to add it to the actual fabric-shim package eventually, similar to the mockstub which is shipped with the Golang shim. Or at least move the maintaining over to the Hyperledger foundation. In order to do this, theres still a few functions to implement. And the package needs to be thoroughly tested, so I encourage you to contribute to it! #makeTestingGreatAgain


We’re not only specialised in Hyperledger Fabric. We also do token sales, smart contract audits and other cool things. Get in touch with TheLedger.


wearetheledger

An awesome collections of stories from our Blockchain experts in Belgium & The Netherlands.

Jonas Snellinckx

Written by

Blockchain developer and consultant @ TheLedger - BigchainDB, Hyperledger Fabric,.. | Occasional writer

wearetheledger

An awesome collections of stories from our Blockchain experts in Belgium & The Netherlands.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade