pallet进阶(11)-test

只是为了测试一个方法,每次总编译项目,慢又麻烦。因此,能够灵活的编写测试用例非常重要

1. pallet

这里就不展示了,找个精简的模板搞就行

2. 编写mock runtime

mock runtime是进行pallet测试时需要提供的runtime,用于在测试环境中为pallet的函数提供必要的运行环境。在需要测试的pallet的src目录下创建mock.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use crate as pallet_use_test;

use frame_support::traits::{ConstU16, ConstU64};
use frame_system as system;
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
};

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;

frame_support::construct_runtime!(
pub enum Test where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,{
System: frame_system,
UseTestDemo: pallet_use_test,
}
);

impl system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
type Origin = Origin;
type Call = Call;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type BlockHashCount = ConstU64<250>;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ConstU16<42>;
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}

impl pallet_use_test::Config for Test {
type Event = Event;
type ClassType = u32;
}

pub use frame_support::pallet_prelude::GenesisBuild;

//此处需要结合`设置genesisconfig`考虑
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut storage = system::GenesisConfig::default().build_storage::<Test>().unwrap().into();
let config: pallet_use_test::GenesisConfig<Test> = pallet_use_test::GenesisConfig { class: 2 };
config.assimilate_storage(&mut storage).unwrap();
storage.into()
}

从上面的代码可以看出,写mock runtime的方式基本上和在runtime/src/lib.rs中加载pallet的写法基本是一样的,只不过在mock runtime中,只加载需要测试的必要的pallet就可以了。另外在配置pallet的时候也只需要能满足测试使用就可以了,而不用配置实际的类型。

3. 设置genesisconfig

在上面的代码中,还创建了一个new_test_ext函数,这个函数中,为测试需要的一些pallet进行初始配置,此处只需要为System进行默认的配置,在实际的测试情况中,往往需要为被测试的pallet以及相关的pallet提供一些初始设置。现在,这里的pallet-use-test还没有genesisConfig。

下面为pallet-use-test添加genesisConfig,在pallet的use-test/src/lib.rs中添加代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//此处一定要test导出
#[cfg(test)]
mod mock;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub class: T::ClassType,
}

#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self { class: Default::default() }
}
}

#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
Class::<T>::put(self.class);
}
}

在上面代码中,为pallet添加了默认的class,而这个配置在实际使用中,需要在chainspec文件里面配置上此值(配置chainspec涉及到node/src/chainspec.rs和chainspec的json文件)。

4. 编写测试函数

mock runtime准备好后就可以写测试函数了,在use-test/src目录下创建一个tests.rs的文件,添加测试函数的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
use super::pallet::Class;
use crate::mock::*;
use frame_support::{assert_noop, assert_ok};
use sp_runtime::traits::BadOrigin;

#[test]
fn test_set_class_info() {
new_test_ext().execute_with(|| {
assert_noop!(UseTestDemo::set_class_info(Origin::signed(1), 42), BadOrigin);
assert_ok!(UseTestDemo::set_class_info(Origin::root(), 42));
assert_eq!(Class::<Test>::get(), 42);
});
}

在测试函数中调用pallet的函数,方式如下: 在mock runtime中定义的模块名字::函数名字(函数参数)
在测试函数中使用pallet的存储,方式如下:

  1. 导出pallet中存储,如上面例子中使用use super::pallet::Class; 导出存储Class;
  2. 像正常在pallet中使用存储一样使用。

5. 运行测试

1
cargo test

6. 总结

本文编辑完毕

  • Copyrights © 2017-2023 Jason
  • Visitors: | Views:

谢谢打赏~

微信