[question] how to mock reactive stack
bilak opened this issue · 10 comments
Please provide the following information:
-
Version of JMockit that was used: 1.49
-
Description of the problem or enhancement request:
I'm trying to mock the results of some repository methods. These methods are returning reactive (Mono/Flux) objects. When I mock more methods in one class all returns the first mock result. I don't understand what is the problem here.
The test sample is here
- Check the following:
-
If a defect or unexpected result, JMockit project members should be able to reproduce it.
For that, include an example test (perhaps accompanied by a Maven/Gradle build script) which
can be executed without changes and reproduces the failure. -
If an enhancement or new feature request, it should be justified by an example test
demonstrating the validity and usefulness of the desired enhancement or new feature. -
The issue does not fall outside the scope of the project (for example, attempting to use
JMockit APIs from Groovy or Scala code, or with an Android runtime). -
The JDK where the problem occurs is a final release, not a development build.
It is a bug. I tested it with @Capturing DemoRepositoryImpl demoRepository
and it works without any problem. So I tried to add times =1
into the Expectations
.
new Expectations() {{
demoRepository.testMethodOne();
result = Mono.just("monoone");
times = 1;
demoRepository.testMethodTwo();
result = Mono.just("monotwo");
times = 1;
}};
and changed an implementation in the method callMonoMethods
to:
@Override
public String callMonoMethods() {
Mono<String> one = demoRepository.testMethodOne();
Mono<String> two = demoRepository.testMethodTwo();
return Mono.zip(one, two)
.map(tuple -> tuple.getT1() + tuple.getT2())
.block();
}
and then an exception is thrown:
Unexpected invocation to:
com.example.demo.data.repository.CustomDemoRepository#testMethodOne()
but it is from a call of testMethodTwo
Can't reproduce the failure without the code under test.
Can't reproduce the failure without the code under test.
@rliesenfeld What you mean by that? Did you run the tests and they are working properly?
Ah ok, now I see all the code is under https://github.com/bilak-poc/jmockit-reactive.
I get org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [com.example.demo.data.repository.DemoRepository demoRepository] in method [void com.example.demo.DemoApplicationTests.testMono(com.example.demo.data.repository.DemoRepository)].
Which, of course, occurs because JMockit isn't getting initialized, due to missing configuration in the pom.xml.
let me fix the example, maybe I just copied something wrong from our application
With a simplified version of the code which still uses the Reactive API (Mono
), it works fine for me:
final class DemoApplicationTests {
@Tested TestService testService;
@Injectable DemoRepository demoRepository;
@Test
void testMono() {
new Expectations() {{
demoRepository.getOne(); result = Mono.just("monoone");
demoRepository.getTwo(); result = Mono.just("monotwo");
}};
var result = testService.callMonoMethods();
assertEquals("monoonemonotwo", result);
}
}
@Service
public final class TestService {
@Autowired private DemoRepository demoRepository;
public String callMonoMethods() {
return Mono.zip(demoRepository.getOne(), demoRepository.getTwo())
.map(tuple -> tuple.getT1() + tuple.getT2())
.block();
}
}
public interface DemoRepository {
Mono<String> getOne();
Mono<String> getTwo();
}
@rliesenfeld I've fixed the config. Why then it's not working with my configuration? We are using mainly integration tests where we are trying to use @Capturing
parameter only for some objects through method parameter. If we use @Capturing
as a test class field then we have other problems.
I think the problem is with combination of Spring Data and JMockit. Spring Data generates Method implementation by JDK proxy.
Yes, it seems related to bytecode generated by the Spring framework. And @Capturing
does not apply to dynamically generated classes.
In this case, the goal was to mock Repository interfaces in integration tests. I suggest to not mock them and just create actual integration tests.