How to start testing your Hyperledger Fabric Nodejs chaincode
⚠️ 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 mockInit
and 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.
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.
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.
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 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 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.
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.