Mockito UnfinishedStubbingException in LamdaFunction - java

I am trying to mock
this.restTemplate =
restTemplateBuilder
.messageConverters(converter)
.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(httpClient))
.build();
I am using following code
doReturn(restTemplateBuilder).when(restTemplateBuilder).messageConverters(any(MappingJackson2HttpMessageConverter.class);
doReturn(restTemplateBuilder).when(restTemplateBuilder).requestFactory(lambdaCaptor.capture());
doReturn(restTemplate).when(restTemplateBuilder).build();
The requestFactory part is giving error
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:

The error
ERROR - org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here
happens because some of these cases:
missing thenReturn()
you are trying to stub a final method, you naughty developer!
you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
I think that your example is close to the third item. You cannot use captor object -> lambdaCaptor.capture() inside a Mockito.when().
Basically, you need to find a way to mock HttpComponentsClientHttpRequestFactory. There might be multiple ways to do it. I would start looking at how to mock the interface that it implements: ClientHttpRequestFactory. Here on the official source code there are some examples. This answer also looks very close to what you need.

Related

How to mock individual methods of a SpyBean?

I'm working on a test class where one specific test needs the actual implementation of a method of a service class that I'm mocking. So I thought, why not use #SpyBean instead of #MockBean and use the actual implementation where I need it (don't have to do anything) and use a mocked implementation where I need it (need to write a one-liner to setup the mocked method).
I've found this great and quite detailed blog post, that explains how to achieve this, section "#SpyBean to the rescue".
The only problem is that it doesn't work, the real implementation is used and those tests succeed, but the mocked methods don't kick in. I'm using Mockito 2.21.0 and Spring Framework 5.1.0. Now I'm using separate test classes for that purpose, but I'd like to figure out how to do this the right way.
I'm pretty much doing exactly the same thing as in the example on this blog:
#SpringBootTest(classes = TestclassAA.class)
class TestclassAA {
#SpyBean
private XXService xxService;
private ClassUsingXXService testee;
#Test
void test1 {
// ..
// use mocked implementation of save() -> does not work, real method called
doReturn(new XXRequestModel()).when(xxService).save(any(XXModel.class));
var result = testee.doSomething();
//..
}
#Test
void test2 {
// ..
// use actual implementation of save() -> works, real method called
var result = testee.doSomething();
//..
}
Basically I'm getting errors messages that hint that what I'm doing isn't possible at all with a spy:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
Anybody any idea how to do this?

How to resolve Unneccessary Stubbing exception

My Code is as below,
#RunWith(MockitoJUnitRunner.class)
public class MyClass {
private static final String code ="Test";
#Mock
private MyClassDAO dao;
#InjectMocks
private MyClassService Service = new MyClassServiceImpl();
#Test
public void testDoSearch() throws Exception {
final String METHOD_NAME = logger.getName().concat(".testDoSearchEcRcfInspections()");
CriteriaDTO dto = new CriteriaDTO();
dto.setCode(code);
inspectionService.searchEcRcfInspections(dto);
List<SearchCriteriaDTO> summaryList = new ArrayList<SearchCriteriaDTO>();
inspectionsSummaryList.add(dto);
when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
verify(dao).doSearchInspections(dto);
}
}
I am getting below exception
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected in test class: Test
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
at org.mockito.internal.exceptions.Reporter.formatUnncessaryStubbingException(Reporter.java:838)
at org.mockito.internal.junit.UnnecessaryStubbingsReporter.validateUnusedStubs(UnnecessaryStubbingsReporter.java:34)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:49)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:103)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Please help me how to resolve
At first you should check your test logic. Usually there are 3 cases. First, you are mocking the wrong method (you made a typo or someone changed tested code so that mocked method is no longer used). Second, your test is failing before this method is called. Third, your logic falls in wrong if/switch branch somewhere in the code so that mocked method is not called.
If this is the first case you always want to change the mocked method for the one used in the code. With the second and the third it depends. Usually you should just delete this mock if it has no use. But sometimes there are certain cases in parametrized tests, which should take this different path or fail earlier. Then you can split this test into two or more separate ones but that's not always good looking. 3 test methods with possibly 3 arguments providers can make your test look unreadable. In that case for JUnit 4 you silent this exception with either
#RunWith(MockitoJUnitRunner.Silent.class)
annotation or if you are using rule approach
#Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);
or (the same behaviour)
#Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
For JUnit 5 tests you can silence this exception using this annotation provided in mockito-junit-jupiter package:
#ExtendWith(MockitoExtension.class)
#MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
Replace #RunWith(MockitoJUnitRunner.class) with #RunWith(MockitoJUnitRunner.Silent.class).
For me neither the #Rule nor the #RunWith(MockitoJUnitRunner.Silent.class) suggestions worked. It was a legacy project where we upgraded to mockito-core 2.23.0.
We could get rid of the UnnecessaryStubbingException by using:
Mockito.lenient().when(mockedService.getUserById(any())).thenReturn(new User());
instead of:
when(mockedService.getUserById(any())).thenReturn(new User());
Needless to say that you should rather look at the test code, but we needed to get the stuff compiled and the tests running first of all ;)
Silent is not a solution. You need fix your mock in your test. See official documentation here.
Unnecessary stubs are stubbed method calls that were never realized during test execution (see also MockitoHint), example:
//code under test:
...
String result = translator.translate("one")
...
//test:
...
when(translator.translate("one")).thenReturn("jeden"); // <- stubbing realized during code execution
when(translator.translate("two")).thenReturn("dwa"); // <- stubbing never realized
...
Notice that one of the stubbed methods were never realized in the code under test, during test execution. The stray stubbing might be an oversight of the developer, the artifact of copy-paste or the effect not understanding the test/code. Either way, the developer ends up with unnecessary test code. In order to keep the codebase clean & maintainable it is necessary to remove unnecessary code. Otherwise tests are harder to read and reason about.
To find out more about detecting unused stubbings see MockitoHint.
when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
verify(dao).doSearchInspections(dto);
The when here configures your mock to do something. However, you donot use this mock in any way anymore after this line (apart from doing a verify). Mockito warns you that the when line therefore is pointless. Perhaps you made a logic error?
Replace
#RunWith(MockitoJUnitRunner.class)
with
#RunWith(MockitoJUnitRunner.Silent.class)
or remove #RunWith(MockitoJUnitRunner.class)
or just comment out the unwanted mocking calls (shown as unauthorised stubbing).
This was already pointed out in this comment, but I think that's too easy to overlook: You may run into an UnnecessaryStubbingException if you simply convert a JUnit 4 test class to a JUnit 5 test class by replacing an existing #Before with #BeforeEach, and if you perform some stubbing in that setup method that is not realized by at least one of the test cases.
This Mockito thread has more information on that, basically there is a subtle difference in the test execution between #Before and #BeforeEach. With #Before, it was sufficient if any test case realized the stubbings, with #BeforeEach, all cases would have to.
If you don't want to break up the setup of #BeforeEach into many small bits (as the comment cited above rightly points out), there's another option still instead of activating the lenient mode for the whole test class: you can merely make those stubbings in the #BeforeEach method lenient individually using lenient().
As others pointed out it is usually the simplest to remove the line that is unnecessarily stubbing a method call.
In my case it was in a #BeforeEach and it was relevant most of the time. In the only test where that method was not used I reset the mock, e.g.:
myMock.reset()
Hope this helps others with the same problem.
(Note that if there are multiple mocked calls on the same mock this could be inconvenient as well since you'll have to mock all the other methods except the one that isn't called.)
Looking at a part of your stack trace it looks like you are stubbing the dao.doSearch() elsewhere. More like repeatedly creating the stubs of the same method.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
Consider the below Test Class for example:
#RunWith(MockitoJUnitRunner.class)
public class SomeTest {
#Mock
Service1 svc1Mock1;
#Mock
Service2 svc2Mock2;
#InjectMock
TestClass class;
//Assume you have many dependencies and you want to set up all the stubs
//in one place assuming that all your tests need these stubs.
//I know that any initialization code for the test can/should be in a
//#Before method. Lets assume there is another method just to create
//your stubs.
public void setUpRequiredStubs() {
when(svc1Mock1.someMethod(any(), any())).thenReturn(something));
when(svc2Mock2.someOtherMethod(any())).thenReturn(somethingElse);
}
#Test
public void methodUnderTest_StateUnderTest_ExpectedBehavior() {
// You forget that you defined the stub for svcMock1.someMethod or
//thought you could redefine it. Well you cannot. That's going to be
//a problem and would throw your UnnecessaryStubbingException.
when(svc1Mock1.someMethod(any(),any())).thenReturn(anyThing);//ERROR!
setUpRequiredStubs();
}
}
I would rather considering refactoring your tests to stub where necessary.
Well, In my case Mockito error was telling me to call the actual method after the when or whenever stub. Since we were not invoking the conditions that we just mocked, Mockito was reporting that as unnecessary stubs or code.
Here is what it was like when the error was coming :
#Test
fun `should return error when item list is empty for getStockAvailability`() {
doAnswer(
Answer<Void> { invocation ->
val callback =
invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
callback.onApiCallError(stockResultViewStateError)
null
}
).whenever(stockViewModelTest)
.getStockAvailability(listOf(), getStocksApiCallBack)
}
then I just called the actual method mentioned in when statement to mock the method.
changes done is as below
stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
#Test
fun `should return error when item list is empty for getStockAvailability`() {
doAnswer(
Answer<Void> { invocation ->
val callback =
invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
callback.onApiCallError(stockResultViewStateError)
null
}
).whenever(stockViewModelTest)
.getStockAvailability(listOf(), getStocksApiCallBack)
//called the actual method here
stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
}
it's working now.
If you're using this style instead:
#Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
replace it with:
#Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
I had UnnecessaryStubbingException when I tried to use the when methods on a Spy object.
Mockito.lenient() silenced the exception but the test results were not correct.
In case of Spy objects, one has to call the methods directly.
#ExtendWith(MockitoExtension.class)
#RunWith(JUnitPlatform.class)
class ArithmTest {
#Spy
private Arithm arithm;
#Test
void testAddition() {
int res = arithm.add(2, 5);
// doReturn(7).when(arithm).add(2, 5);
assertEquals(res, 7);
}
}
In case of a large project, it's difficult to fix each of these exceptions. At the same time, using Silent is not advised. I have written a script to remove all the unnecessary stubbings given a list of them.
https://gist.github.com/cueo/da1ca49e92679ac49f808c7ef594e75b
We just need to copy-paste the mvn output and write the list of these exceptions using regex and let the script take care of the rest.
If you use any() when mocking, you have to relpace #RunWith(MockitoJUnitRunner.class) with
#RunWith(MockitoJUnitRunner.Silent.class).

anyString() in mockito is throwing an invalid use of argument matchers

I am using eclipse to run some unit tests on a class and I am using Mockito so I don't have to connect to the database. I have used anyString() in other tests which works but it isn't working in this test. If I change it from anyString() to "" the error disappears and the test passes.
My test is:
#Test
public void test_GetUserByUsername_CallsCreateEntityManager_WhenAddUserMethodIsCalled() {
//Arrange
EntityManagerFactory mockEntityManagerFactory = mock(EntityManagerFactory.class);
EntityManager mockEntityManager= mock(EntityManager.class);
UserRepositoryImplementation userRepositoryImplementation = new UserRepositoryImplementation();
userRepositoryImplementation.setEntityManagerFactory(mockEntityManagerFactory);
when(mockEntityManagerFactory.createEntityManager()).thenReturn(mockEntityManager);
//Act
userRepositoryImplementation.getUserByUsername(anyString());
//Assert
verify(mockEntityManagerFactory, times(1)).createEntityManager();
}
Can anyone explain why I am getting the error and what I can do to resolve it?
userRepositoryImplementation.getUserByUsername(anyString());
This is not the right use of anyString().
It can be used for stubbing or for verifying. But not for actual call of method.
From documentation:
Allow flexible verification or stubbing.
If you want a random string when test is running try to use RandomStringUtils or any other similar library.
userRepositoryImplementation.getUserByUsername(RandomStringUtils.random(length));
You can use Matchers, like anyString() for mocking up (stubbing) an object. I.e. inside a when() invocation. Your invocation is an actual invocation:
//Act
userRepositoryImplementation.getUserByUsername(anyString());
So that's right: for testing you have to add some real input, like "", "salala" or null.

Spock: test name and outcome in setup() cleanup() methods

I am wondering if it is possible to make the following data available in a Spock test's lifecycle methods:
test name in the setup() method
test name and test outcome in the cleanup() method
The reason I am asking is that I would like send these metadata to a data sink without the need to touch each and every test.
Thanks!
Martin
Try this.specificationContext.iterationInfo.name in setup(). Not sure if it works. In general specificationContext is the place where I'd be looking for such data.
Update from Opal's answer:
It is now (Spock 1.1) specificationContext.currentIteration.name
For the record, you could also use
#Rule
TestName testName = new org.junit.rules.TestName()
...
println "name: $testName.methodName"
... but there seems no point.
For the other question, getting the outcome: I couldn't find a way of getting this from Spock's SpecificationContext.
I took a quick look at org.junit.rules.TestWatcher ... but with Spock this seemed unable to detect a failed test.

Mockito exception in doThrow that looks correct

I'm trying to mock a method to see if I handle an exception correctly. This is as far as I get.
interface:
interface SampleManager {
void deleteVariome(String specimenId, String analysisId) throws Exception;
// ...
}
unit test:
// ...
SampleManger sampleManager = mock(SampleManager.class);
// below is line 753
doThrow(Exception.class).when(sampleManager).deleteVariome(sample1.getId(), analysisId);
result:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at ...server.ArchiveManagerImplUTest.deleteVariomeFails(ArchiveManagerImplUTest.java:753)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod(); <-- this looks a log like what I did!
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer! <-- I have a lot of other mocks of this interface in this test that work.
From an identical issue that I just ran into, I suspect that sample is a mock, and you stubbed sample.getId() elsewhere? That caused this problem in my case, anyhow.
For some reason, Mockito gets upset if one of the arguments you pass to the stub used with doThrow in this way is the result of a method you also mocked. Perhaps it's a re-entrancy check of sorts to avoid infinite loops, I don't know.
Regardless, try replacing sample.getId() with a constant value and that should solve the issue. You could consider using a constant declared in your test for both the mock and any further uses of it. You could then also check that sample.getId() was used by the method you're testing by adding another call to verify.
This error is usually reported AFTER the place where it actually occurred. If you fail to stub something properly, Mockito usually can't tell until the NEXT time you call one of the Mockito methods. This might be in the same test method, a later test method in the same class, or even an entirely different test class.
The line that you've quoted looks fine to me. Take a look at the lines above it, where you call a Mockito stubbing or verification method. It's very likely that you have a when that has no associated thenReturn, then or thenThrow. Or you might have a verify that's missing the actual method call. There are a few other possibilities too.
If you can't find an error in the lines ABOVE the one that you've quoted, then post some more of your code, and I'll take a closer look.
As described in the answer by Gijs, this is probably due to a bug in Mockito. Here is a complete test which reproduces it:
interface Sample { String getId(); }
interface SampleManager {
void deleteVariome(String specimenId, String analysisId);
}
#Test
public void probableMockitoBug() {
Sample sample1 = mock(Sample.class);
when(sample1.getId()).thenReturn("a");
SampleManager manager = mock(SampleManager.class);
doThrow(Exception.class).when(manager).deleteVariome(sample1.getId(), "b");
manager.deleteVariome("a", "b");
}
The test produces the following output:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at org.mockitousage.JavadocExamplesTest.probableMockitoBug(JavadocExamplesTest.java:404)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
at org.mockito.exceptions.Reporter.unfinishedStubbing(Reporter.java:55)
at org.mockito.internal.progress.MockingProgressImpl.validateState(MockingProgressImpl.java:74)
at org.mockito.internal.progress.ThreadSafeMockingProgress.validateState(ThreadSafeMockingProgress.java:49)
at org.mockito.internal.MockHandler.handle(MockHandler.java:71)
at org.mockito.internal.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:36)
at org.mockito.internal.creation.MethodInterceptorFilter.intercept(MethodInterceptorFilter.java:48)
at org.mockitousage.JavadocExamplesTest$Sample$$EnhancerByMockitoWithCGLIB$$d5ac41.getId()
at org.mockitousage.JavadocExamplesTest.probableMockitoBug(JavadocExamplesTest.java:404)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
you have to supply an instance of the Exception.class not the Exception class itself.
doThrow(new Exception()).when(sampleManager).deleteVariome(sample1.getId(), analysisId);
EDIT
Well #DavidWallace corrected me, so be warned (or rather enlightened) that since 1.9 you can just provide the exception class to throw and it will construct one for you.

Categories