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

Feature request: create a spy! macro to provide a transparent mock but that can be asserted upon. #567

Open
iddm opened this issue Apr 16, 2024 · 6 comments

Comments

@iddm
Copy link

iddm commented Apr 16, 2024

Similar to Java unit testing frameworks, it would have been nice to have a "spy" object that can be asserted upon: call counts with specific kind (or any) arguments, capturing arguments, and so on. Currently, we only have the mock! macro but then we will have to provide our own implementation. It would have been nice to have a spy! macro which, for example, would provide a "spying" implementation of a trait, based on some already existing implementation, which we would later just use.

@asomers
Copy link
Owner

asomers commented Apr 16, 2024

Could you explain in more detail what spy! would do? I'm unfamiliar with this Java library.

@iddm
Copy link
Author

iddm commented Apr 16, 2024

Would this guide be of help? https://www.baeldung.com/mockito-spy

@asomers
Copy link
Owner

asomers commented Apr 16, 2024

So it wraps a real object, but records all of its calls for later inspection? I'm sure there would be s lot of hard cases. What about static methods? Generic methods?

@iddm
Copy link
Author

iddm commented Apr 16, 2024

So it wraps a real object, but records all of its calls for later inspection? I'm sure there would be s lot of hard cases. What about static methods? Generic methods?

It is almost the same as a mock, but it has a real object inside, and yes, it records all the info for later inspection. As for the static methods, there are two ways:

  1. Code generation, where the static methods are also mocked the same way as an ordinary method.
  2. An error is thrown.

Both of these are utilised in different Java frameworks. For example, the Spring framework doesn't care about the types at all: if it sees that an object can be changed fully without the code generation, it does just that; if it sees that the object is impossible to replace without the code generation, it utilises the same interface of the needed object to generate the code which does the required job. This is the mechanism for the bean injection: by an interface of implementation. Various unit testing frameworks also do one thing or another, so it depends.

The generic types are flattened, the same as when the compiler flattens it for a single symbol name. The generics are always parametrised, so there must be a parametrised mock, there can't be a non-parametrised mock.

As for this crate, I suggest we have a more versatile method where we also generate the code in case it is required.

@asomers
Copy link
Owner

asomers commented Apr 16, 2024

What do you mean "without the code generation"? How would any of this work without code generation?

@iddm
Copy link
Author

iddm commented Apr 16, 2024

What do you mean "without the code generation"? How would any of this work without code generation?

Without generating a completely new code for the same type, which does exactly what the original one does, with or without decorating. I meant the code generation in Java terms, not in Rust terms. Of course, we always generate code in Rust here, but in Java, for the mocks, we can implement the interface and exploit the difference in behaviour this way, while for a concrete type (or any other type that can't be mocked any other way), we can only regenerate the code and either wrap the real object inside and delegate the calls to it, or copy-paste the code from the original implementation using the language reflection mechanisms to inline it into the just-generated type. So, please, don't be confused with the "code generation" from Java, just ignore it then.

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