At this point your code should be compiling, although we did not test if it works.
You can deploy the code to the chain everytime when you make a change. But come on, your time is more valuable than that.
Also, good to keep the contract break-free and tested for future changes.
For each test, test specific variables such as block time, state must be mocked. Write a function for easy setup.
Copy
#[test]fnproper_initialization(){letmut deps =mock_dependencies(&[]);let msg =InitMsg{
counter_offer:coins(40,"ETH"),
expires:100_000,};let info =mock_info("creator",&coins(1,"BTC"));// we can just call .unwrap() to assert this was a successlet res =init(deps.as_mut(),mock_env(), info, msg).unwrap();assert_eq!(0, res.messages.len());// it worked, let's query the statelet res =query_config(deps.as_ref()).unwrap();assert_eq!(100_000, res.expires);assert_eq!("creator", res.owner.as_str());assert_eq!("creator", res.creator.as_str());assert_eq!(coins(1,"BTC"), res.collateral);assert_eq!(coins(40,"ETH"), res.counter_offer);}
Good we now have a test environment initializer. This is a very simple one, you can pass in variables to the function and do different tweaks.
Check cosmwasm-plus for more.
# Mock Dependencies, Environment, and Message Info
There are two three mocking tools we should improve on:
Copy
/// All external requirements that can be injected for unit tests./// It sets the given balance for the contract itself, nothing elsepubfnmock_dependencies(
contract_balance:&[Coin],)->OwnedDeps<MockStorage,MockApi,MockQuerier>{let contract_addr =HumanAddr::from(MOCK_CONTRACT_ADDR);OwnedDeps{
storage:MockStorage::default(),
api:MockApi::default(),
querier:MockQuerier::new(&[(&contract_addr, contract_balance)]),}}
This sets up dependencies for testing such as storage, api, and querier.
Copy
/// Returns a default enviroment with height, time, chain_id, and contract address/// You can submit as is to most contracts, or modify height/time if you want to/// test for expiration.////// This is intended for use in test code only.pubfnmock_env()->Env{Env{
block:BlockInfo{
height:12_345,
time:1_571_797_419,
time_nanos:879305533,
chain_id:"cosmos-testnet-14002".to_string(),},
contract:ContractInfo{
address:HumanAddr::from(MOCK_CONTRACT_ADDR),},}}
mock_env is for mocking block, and contract environment.
Copy
/// Just set sender and sent funds for the message. The essential for/// This is intended for use in test code only.pubfnmock_info<U:Into<HumanAddr>>(sender:U, sent:&[Coin])->MessageInfo{MessageInfo{
sender: sender.into(),
sent_funds: sent.to_vec(),}}
Copy
#[test]fntransfer(){letmut deps =mock_dependencies(&[]);let msg =InitMsg{
counter_offer:coins(40,"ETH"),
expires:100_000,};let info =mock_info("creator",&coins(1,"BTC"));// we can just call .unwrap() to assert this was a successlet res =init(deps.as_mut(),mock_env(), info, msg).unwrap();assert_eq!(0, res.messages.len());// random cannot transferlet info =mock_info("anyone",&[]);let err =handle_transfer(deps.as_mut(),mock_env(), info,HumanAddr::from("anyone")).unwrap_err();match err {ContractError::Unauthorized{}=>{}
e =>panic!("unexpected error: {}", e),}// owner can transferlet info =mock_info("creator",&[]);let res =handle_transfer(deps.as_mut(),mock_env(), info,HumanAddr::from("someone")).unwrap();assert_eq!(res.attributes.len(),2);assert_eq!(res.attributes[0],attr("action","transfer"));// check updated properlylet res =query_config(deps.as_ref()).unwrap();assert_eq!("someone", res.owner.as_str());assert_eq!("creator", res.creator.as_str());}