1

In testing my pallet, I have some function that stores something and deposits an event.

    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        ThingStored(thing<T>, T::AccountId),
    }

    #[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
    pub fn create_thing(origin: OriginFor<T>) -> DispatchResult {
        let creator = ensure_signed(origin)?;
        let id = 1;

        let thing = Thing {
            id,
            creator: creator.clone()
        };

        // Update storage.
        <Things<T>>::insert(id, thing.clone());

        // Emit an event.
        Self::deposit_event(Event::ThingStored(thing, creator.clone()));
        Ok(())
    }

In my pallet tests, I am calling the function and would like to assert that the event deposited contains the correct data.

#[test]
fn it_works_for_default_value() {
    new_test_ext().execute_with(|| {
        // Dispatch a signed extrinsic.
        assert_ok!(ThingsModule::create_thing(Origin::signed(1)));
        let event = <frame_system::Pallet<Test>>::events().pop()
            .expect("Expected at least one EventRecord to be found").event;
        // How can I access the `Thing` object from the event? I'll also then use it to read from storage
        // assert_eq!(ThingsModule::things(thing.creator).unwrap().creator, 1);
    });
}

1 Answer 1

2

The FRAME System pallet has two helper functions for this:

/// Assert the given `event` exists.
#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
pub fn assert_has_event(event: T::Event) {
    assert!(Self::events().iter().any(|record| record.event == event))
}

/// Assert the last event equal to the given `event`.
#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
pub fn assert_last_event(event: T::Event) {
    assert_eq!(Self::events().last().expect("events expected").event, event);
}

You can see a lot of examples of these functions being used by searching the Substrate codebase, but here is one simple example:

System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into());

Note the .into() at the end which converts a Pallet specific event to a more general T::Event.

3
  • Ok, these are useful! For my test, I'm also hoping to read the inner data from the event. Is that possible to use Self::events().last().expect("events expected").event.0 to get the Thing? Jun 21, 2022 at 15:34
  • 1
    It is technically possible, but not that ergonomic since there is a lot of type wrapping happening here, and you cannot just reach into an object without concrete type stuff. Best to assume what the value would be, and insert that into the test which verifies that the inner value matches what is expected.
    – Shawn Tabrizi
    Jun 21, 2022 at 15:46
  • 1
    If you want an example of the complex matching, you can open a new question :)
    – Shawn Tabrizi
    Jun 21, 2022 at 15:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.