Giter Site home page Giter Site logo

Comments (4)

asomers avatar asomers commented on July 21, 2024

run is definitely getting called. That's why pre_execute is being called, after all. And pre_execute panics because you never set any expectations for it. Unless you're using the nightly flag, you need to add some variation of .returning to every expectation . I'm actually surprised that this compiles. There shouldn't be any method bodies inside of mock!, because they don't do anything there.

from mockall.

naftulikay avatar naftulikay commented on July 21, 2024

@asomers thanks for your response! I have updated my test code and I'm still seeing the failure.

tests.rs:

use anyhow::Result;
use mockall::mock;

use super::Command;

mock! {
    PreExecFailure{}
    impl Command for PreExecFailure {
        // mock these three methods only, not run
        async fn pre_execute(&self) -> Result<()>;
        async fn execute(&self) -> Result<()>;
        async fn post_execute(&self, result: Result<()>) -> Result<()>;
    }
}

#[tokio::test]
async fn test_pre_exec_failure() {
    let mut mock = MockPreExecFailure::new();
    mock.expect_pre_execute().returning(|| Err(anyhow::anyhow!("Error")));
    mock.expect_execute().returning(|| Ok(()));
    mock.expect_post_execute().returning(|_r| Ok(()));

    assert!(mock.run().await.is_err(), "Command::run should have returned an error on failed pre_execute");

    // execute should never have been called
    mock.expect_execute().never();

    // pre-execute should have been called once
    mock.expect_pre_execute().times(1);
}

The other source file has not changed.

Here is the failed output:

MockPreExecFailure::pre_execute: Expectation(<anything>) called 0 time(s) which is fewer than expected 1

I can observe that execute was never called, but pre_execute was never called according to the mock. With debug points, I can see that pre_execute was indeed called, but I don't know why it doesn't register as having been called.

from mockall.

asomers avatar asomers commented on July 21, 2024

You can't set expectations after calling the code under test. Mockall doesn't work that way. You have to set them before.

from mockall.

naftulikay avatar naftulikay commented on July 21, 2024

I was able to resolve the issue, full code:

tests.rs:

use anyhow::{anyhow, Result};
use mockall::mock;

use super::Command;

mock! {
    Exec{}
    impl Command for Exec {
        // mock these three methods only, not run
        async fn pre_execute(&self) -> Result<()>;
        async fn execute(&self) -> Result<()>;
        async fn post_execute(&self, result: Result<()>) -> Result<()>;
    }
}

/// A pre-exec failure should mean that exec is never called, nor post-exec
#[tokio::test]
async fn test_pre_exec_failure() {
    let mut mock = MockExec::new();
    // pre execute should be called and fail
    mock.expect_pre_execute()
        .once()
        .returning(|| Err(anyhow::anyhow!("Error")));
    // execute should never be called
    mock.expect_execute().never().returning(|| Ok(()));
    // post execute should never be called
    mock.expect_post_execute().never().returning(|_r| Ok(()));

    // run it
    assert!(
        mock.run().await.is_err(),
        "Command::run should have returned an error on failed pre_execute"
    );
}

/// An exec failure combined with post-exec propagation, should fail
#[tokio::test]
async fn test_exec_failure() {
    let mut mock = MockExec::new();

    // pre execute should be called and succeed
    mock.expect_pre_execute().once().returning(|| Ok(()));
    // execute should be called and fail
    mock.expect_execute()
        .once()
        .returning(|| Err(anyhow!("Fail")));
    // post execute should be called with an error
    mock.expect_post_execute()
        .withf(|r| r.is_err() && r.as_ref().is_err_and(|e| e.to_string().eq("Fail")))
        .returning(|r| r);

    // run it
    assert!(
        mock.run().await.is_err(),
        "Command::run should have returned an error on failed execute/post-execute"
    );
}

/// An exec failure should be able to be recovered by post exec
#[tokio::test]
async fn test_post_exec_recover() {
    let mut mock = MockExec::new();

    // pre execute should be called and succeed
    mock.expect_pre_execute().once().returning(|| Ok(()));
    // execute should be called and fail
    mock.expect_execute()
        .once()
        .returning(|| Err(anyhow!("Fail")));
    // post execute should be called, receive an error, and recover
    mock.expect_post_execute()
        .withf(|r| r.is_err() && r.as_ref().is_err_and(|e| e.to_string().eq("Fail")))
        .returning(|_r| Ok(()));

    // run it
    assert!(
        mock.run().await.is_ok(),
        "Command::run should have recovered from error in post exec"
    );
}

I wasn't aware that expectations were evaluated on drop(), I had assumed that you configured the mock first, ran the code, and then after running, validate the assumptions.

from mockall.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.