rollbear / trompeloeil

Header only C++14 mocking framework
Boost Software License 1.0
802 stars 85 forks source link

Refactoring with sequenced expectations #318

Closed sjgriffin7 closed 10 months ago

sjgriffin7 commented 10 months ago

I'm having some issues with refactoring sequenced calls. (Note: I'm using Catch2 as the unit test framework, and currently using C++11)

Ideally, I'd be able to take a test like this:

TEST_CASE("Refactoring","[refactoring]")
{
    Obj* obj = new Obj(); // Assume Obj::MethodA() and Obj::MethodB() are defined

    SECTION("Original")
    {
        // - - - Expectation - - - //

        trompeloeil::sequence seq;

        REQUIRE_CALL_V(  obj, MethodA(),
            .IN_SEQUENCE( seq )
        );

        REQUIRE_CALL_V(  obj, MethodB(),
            .IN_SEQUENCE( seq )
        );

        // - - - Execution - - - //

        obj->MethodA();
        obj->MethodB();
    }

}

And add a helper function to reuse REQUIRE_CALL_V() statements:

void REQUIRE_MethodB(Obj* obj_, trompeloeil::sequence &seq)
{
    REQUIRE_CALL_V( obj_, MethodB(), .IN_SEQUENCE( seq ) );
}

TEST_CASE("Refactoring","[refactoring]")
{
    Obj* obj = new Obj(); // Assume Obj::MethodA() and Obj::MethodB() are defined

    SECTION("Original")
    {
        // - - - Expectation - - - //

        trompeloeil::sequence seq;

        REQUIRE_CALL_V(  obj, MethodA(),
            .IN_SEQUENCE( seq )
        );

        REQUIRE_CALL_V(  obj, MethodB(),
            .IN_SEQUENCE( seq )
        );

        // - - - Execution - - - //

        obj->MethodA();
        obj->MethodB();
    }

    SECTION("Refactored")
    {
        // - - - Expectation - - - //

        trompeloeil::sequence seq;

        REQUIRE_CALL_V(  obj, MethodA(),
            .IN_SEQUENCE( seq )
        );

        REQUIRE_MethodB(obj, seq);

        // - - - Execution - - - //

        obj->MethodA();
        obj->MethodB();
    }

}

My issue arises in the SECTION("Refactored") results, which reports unfulfilled expectations for MethodA() and MethodB().

Is this something that should work, or are there other recommendations for refactoring? Any details on the inner workings of trompeloeil::sequence are also welcome.

rollbear commented 10 months ago

REQUIRE_CALL() and its siblings are valid until the end of the scope, so your function REQUIRE_MethodB() sets a requirement for a call, that immediately fails because the requirement is checked at the end of the function. I don't expect the sequence to be of importance here.

See NAMED_REQUIRE_CALL.

Example: https://godbolt.org/z/fY6v39vKa

sjgriffin7 commented 10 months ago

Excellent, that was the piece of info I was missing. Thanks!