Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting expectations in a function fails #311

Open
ninkibah opened this issue Sep 13, 2023 · 6 comments
Open

Setting expectations in a function fails #311

ninkibah opened this issue Sep 13, 2023 · 6 comments

Comments

@ninkibah
Copy link

ninkibah commented Sep 13, 2023

I have a very large class I want to mock, and I created a function to set all these expectations, which I then call from the test.

Sadly, this always fails. It would appear that the ALLOW_CALL invocations create local expectation objects which need to be alive when the mock is used.

I appreciate that this might be a very large change to make to the library, but if not, this should be documented in the FAQ.

Here's my sample code:

#include <catch2/catch_test_macros.hpp>
#include <catch2/trompeloeil.hpp>

struct Real {
  virtual int func() const = 0;
  virtual ~Real() = default;
};

struct Mock : public Real {
  MAKE_MOCK0(func, int(), const);
  ~Mock() override = default;
};

void setupExpectations(Mock& obj) {
  ALLOW_CALL(obj, func()).RETURN(1729);
}

TEST_CASE("Expectations in their own function") {
  Mock mock;
  setupExpectations(mock);

  REQUIRE(mock.func() == 1729); // Throws exception saying No match for call of func with signature int() with.
}

TEST_CASE("Expectations in test") {
  Mock mock;
  ALLOW_CALL(mock, func()).RETURN(1729);

  REQUIRE(mock.func() == 1729); // This works fine, of course!
}
@rollbear
Copy link
Owner

All expectations set up are valid in the scope of the set up, so ALLOW_CALL() in setupExpectations() is alive until the end of the function setupExpectations() and therefore no longer available in the line of the comment.

You can use NAMED_ALLOW_CALL() to bind the expectation to a variable that you choose maintain the lifetime of.

@ninkibah
Copy link
Author

Thanks for the quick answer.

I went looking for examples with NAMED_ALLOW_CALL and didn't find any, but I guess it would look something like the folowing:

struct Real {
  virtual int func() const = 0;
  virtual ~Real() = default;
};

struct Mock : public Real {
  MAKE_MOCK0(func, int(), const);
  ~Mock() override = default;
};

auto setupExpectations(Mock& obj) {
  return NAMED_ALLOW_CALL(obj, func()).RETURN(1729);
}

TEST_CASE("Expectations in their own function") {
  Mock mock;
  auto expectation = setupExpectations(mock);

  REQUIRE(mock.func() == 1729); // Throws exception saying No match for call of func with signature int() with.
}

However, my mock needs 10-15 expectations (don't ask), so I guess I will have to create a vector of std::vector<std::unique_ptr<expectation>> and push each NAMED_ALLOW_CALL into it, and then return the vector. This is a bit ugly. I suspect that people rarely use this feature.

Tomorrow, I'll make a PR for a documentation change to help other people.

@rollbear
Copy link
Owner

That looks right. I've done it that way too. The vector is nice. I'm a bit surprised that you didn't find any examples of NAMED_ALLOW_CALL. Here's the entry in the reference manual: https://github.com/rollbear/trompeloeil/blob/main/docs/reference.md#NAMED_ALLOW_CALL, with an example. I guess there's not a good enough entry point to find it?

@ninkibah
Copy link
Author

I was looking in the cookbook, which seemed the best place to start. All the examples there were ALLOW_CALL or REQUIRE_CALL, so I presumed that's what I should use. I'll add a section there tomorrow, when I have time.

@ninkibah
Copy link
Author

Good to see that I hadn't found missing functionality in your library :-)

@rollbear
Copy link
Owner

rollbear commented Nov 7, 2023

Is there something I should do here, or can I close the issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants