fabric-samples/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go
Brett Logan 426cdf1f98 Add Tests and Mocks To Asset Transfer Chaincode
Many users raise questions on how to test chaincode. It used
to be much easier with the old shim, as they could directly
use the old mock stub in the shim. Now that it no longer exists
the fabcar example can provide an example of how to test chaincode.

Also worth noting is our current directory structure of our Go
chaincodes prevents the creation of mocks due to import cycles.
This change also pushes the chaincode logic down into a `chaincode`
package.

Signed-off-by: Brett Logan <brett.t.logan@ibm.com>
2020-07-10 05:59:22 -04:00

184 lines
6.7 KiB
Go

package chaincode_test
import (
"encoding/json"
"fmt"
"testing"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
"github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode"
"github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode/mocks"
"github.com/stretchr/testify/require"
)
//go:generate counterfeiter -o mocks/transaction.go -fake-name TransactionContext . transactionContext
type transactionContext interface {
contractapi.TransactionContextInterface
}
//go:generate counterfeiter -o mocks/chaincodestub.go -fake-name ChaincodeStub . chaincodeStub
type chaincodeStub interface {
shim.ChaincodeStubInterface
}
//go:generate counterfeiter -o mocks/statequeryiterator.go -fake-name StateQueryIterator . stateQueryIterator
type stateQueryIterator interface {
shim.StateQueryIteratorInterface
}
func TestInitLedger(t *testing.T) {
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
assetTransfer := chaincode.SmartContract{}
err := assetTransfer.InitLedger(transactionContext)
require.NoError(t, err)
chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key"))
err = assetTransfer.InitLedger(transactionContext)
require.EqualError(t, err, "failed to put to world state. failed inserting key")
}
func TestCreateAsset(t *testing.T) {
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
assetTransfer := chaincode.SmartContract{}
err := assetTransfer.CreateAsset(transactionContext, "", "", "", 0, 0)
require.NoError(t, err)
chaincodeStub.GetStateReturns([]byte{}, nil)
err = assetTransfer.CreateAsset(transactionContext, "asset1", "", "", 0, 0)
require.EqualError(t, err, "the asset asset1 already exists")
chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset"))
err = assetTransfer.CreateAsset(transactionContext, "asset1", "", "", 0, 0)
require.EqualError(t, err, "failed to read from world state: unable to retrieve asset")
}
func TestReadAsset(t *testing.T) {
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
expectedAsset := &chaincode.Asset{ID: "asset1"}
bytes, err := json.Marshal(expectedAsset)
require.NoError(t, err)
chaincodeStub.GetStateReturns(bytes, nil)
assetTransfer := chaincode.SmartContract{}
asset, err := assetTransfer.ReadAsset(transactionContext, "")
require.NoError(t, err)
require.Equal(t, expectedAsset, asset)
chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset"))
_, err = assetTransfer.ReadAsset(transactionContext, "")
require.EqualError(t, err, "failed to read from world state: unable to retrieve asset")
chaincodeStub.GetStateReturns(nil, nil)
asset, err = assetTransfer.ReadAsset(transactionContext, "asset1")
require.EqualError(t, err, "the asset asset1 does not exist")
require.Nil(t, asset)
}
func TestUpdateAsset(t *testing.T) {
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
expectedAsset := &chaincode.Asset{ID: "asset1"}
bytes, err := json.Marshal(expectedAsset)
require.NoError(t, err)
chaincodeStub.GetStateReturns(bytes, nil)
assetTransfer := chaincode.SmartContract{}
err = assetTransfer.UpdateAsset(transactionContext, "", "", "", 0, 0)
require.NoError(t, err)
chaincodeStub.GetStateReturns(nil, nil)
err = assetTransfer.UpdateAsset(transactionContext, "asset1", "", "", 0, 0)
require.EqualError(t, err, "the asset asset1 does not exist")
chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset"))
err = assetTransfer.UpdateAsset(transactionContext, "asset1", "", "", 0, 0)
require.EqualError(t, err, "failed to read from world state: unable to retrieve asset")
}
func TestDeleteAsset(t *testing.T) {
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
asset := &chaincode.Asset{ID: "asset1"}
bytes, err := json.Marshal(asset)
require.NoError(t, err)
chaincodeStub.GetStateReturns(bytes, nil)
chaincodeStub.DelStateReturns(nil)
assetTransfer := chaincode.SmartContract{}
err = assetTransfer.DeleteAsset(transactionContext, "")
require.NoError(t, err)
chaincodeStub.GetStateReturns(nil, nil)
err = assetTransfer.DeleteAsset(transactionContext, "asset1")
require.EqualError(t, err, "the asset asset1 does not exist")
chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset"))
err = assetTransfer.DeleteAsset(transactionContext, "")
require.EqualError(t, err, "failed to read from world state: unable to retrieve asset")
}
func TestTransferAsset(t *testing.T) {
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
asset := &chaincode.Asset{ID: "asset1"}
bytes, err := json.Marshal(asset)
require.NoError(t, err)
chaincodeStub.GetStateReturns(bytes, nil)
assetTransfer := chaincode.SmartContract{}
err = assetTransfer.TransferAsset(transactionContext, "", "")
require.NoError(t, err)
chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset"))
err = assetTransfer.TransferAsset(transactionContext, "", "")
require.EqualError(t, err, "failed to read from world state: unable to retrieve asset")
}
func TestGetAllAssets(t *testing.T) {
asset := &chaincode.Asset{ID: "asset1"}
bytes, err := json.Marshal(asset)
require.NoError(t, err)
iterator := &mocks.StateQueryIterator{}
iterator.HasNextReturnsOnCall(0, true)
iterator.HasNextReturnsOnCall(1, false)
iterator.NextReturns(&queryresult.KV{Value: bytes}, nil)
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
chaincodeStub.GetStateByRangeReturns(iterator, nil)
assetTransfer := &chaincode.SmartContract{}
assets, err := assetTransfer.GetAllAssets(transactionContext)
require.NoError(t, err)
require.Equal(t, []chaincode.QueryResult{{Record: asset}}, assets)
iterator.HasNextReturns(true)
iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item"))
assets, err = assetTransfer.GetAllAssets(transactionContext)
require.EqualError(t, err, "failed retrieving next item")
require.Nil(t, assets)
chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets"))
assets, err = assetTransfer.GetAllAssets(transactionContext)
require.EqualError(t, err, "failed retrieving all assets")
require.Nil(t, assets)
}