I have fairly simple Test case below which is passing when I use the Mockito 1.19 version but failing when I switched to Mockito 3.x.
#Test(expected = DBMapperRetryableException.class)
public void testUpdateInventoryWithException() throws DBMapperRetryableException, DBMapperNonRetryableException {
when(baseDBOperations.partialUpdate(anyString(), any(PrimaryKey.class), anyString(), anyString(), any(ReturnValue.class), any(ValueMap.class))).thenThrow(new DBMapperRetryableException("Exception", new Throwable()));
assertNull(prebookInventoryDao.updateInventory(PrebookInventoryUpdateInfo.builder().hashKey(DUMMY).sortKey(123).incrementValue(1).build()));
// verify(baseDBOperations, times(1)).partialUpdate(anyString(), any(PrimaryKey.class), anyString(), anyString(), any(ReturnValue.class), any(ValueMap.class));
}
Above shows the below message when I run it on Intellij:
[MockitoHint] PrebookInventoryDaoTest.testUpdateInventoryWithException (see javadoc for MockitoHint):
[MockitoHint] 1. Unused... -> at com.amazon.pbxcoreservice.dao.PrebookInventoryDaoTest.testUpdateInventoryWithException(PrebookInventoryDaoTest.java:68)
[MockitoHint] ...args ok? -> at com.amazon.pbxcoreservice.dao.PrebookInventoryDao.updateInventory(PrebookInventoryDao.java:51)
Error shown: java.lang.AssertionError: Expected exception: com.amazon.pbxcoreservice.dynamodb.exception.DBMapperRetryableException
Here's the PrebookInventoryDao class. I've skipped a few methods like getUpdateExpression, getPrimaryKey.
public class PrebookInventoryDao {
private final BaseDBOperations baseDBOperations;
public PrebookInventoryDao(final BaseDBOperations baseDBOperations) {
this.baseDBOperations = baseDBOperations;
}
public UpdateItemOutcome updateInventory(PrebookInventoryUpdateInfo prebookInventoryUpdateInfo)
throws DBMapperRetryableException, DBMapperNonRetryableException {
ConditionalExpressionRequest conditionalExpressionRequest = prebookInventoryUpdateInfo.getConditionalExpressionRequest();
String conditionalExpression = conditionalExpressionRequest != null ? conditionalExpressionRequest.getQuery() : null;
return baseDBOperations.partialUpdate(DynamoDBConstants.PREBOOK_INVENTORY.TABLE,
getPrimaryKey(prebookInventoryUpdateInfo), getUpdateExpression(),
conditionalExpression, ReturnValue.UPDATED_NEW, getValueMap(prebookInventoryUpdateInfo, conditionalExpressionRequest));
}
Could anyone help as to why such discrepancy?
PS: Looks like when I use when(baseDBOperations.partialUpdate(any(), any(), any(), any(), any(), any())).thenThrow(new DBMapperRetryableException("Exception", new Throwable()));
, then the test passes. Not sure why when(baseDBOperations.partialUpdate(anyString(), any(PrimaryKey.class), anyString(), anyString(), any(ReturnValue.class), any(ValueMap.class))).thenThrow(new DBMapperRetryableException("Exception", new Throwable())); isn't working.
Related
I am writing unit tests for one of our reactive methods. This method depends on another service. I have mocked this service. While running the test, i am getting the below error:
java.lang.AssertionError: expectation "expectError(Class)" failed (expected: onError(MyException); actual: onComplete()).
Here is what I have tried:
Method(ReactiveService.class):
#Autowired
private Service serice;
public Mono<MyObject> save(List<MyObject> arg1, String arg2) {
return SomeUtil.user()
.map(user -> service.save(arg1, arg2, user))
.subscribeOn(scheduler)
.doOnError(e -> {
throw new MyException(MyObject.class, "save object", e);
});
}
Test:
#Mock
Service service;
#InjectMocks
ReactiveService reactiveService;
#Test
public void unit_test(){
when(service.save(any(), any(), any())).thenThrow(new RuntimeException());
Mono<MyObject> result = reactiveService.save(arg1, arg2);
StepVerifier.create(result)
.expectError(MyException.class)
.verify();
}
From the error I understood that, no signal is received from the method. But I am not getting what I have missed here.
I think that the issue you have is caused by SomeUtil.user() not emitting a value.
Why do I think it's the case: I have tried out a simple example to reproduce your issue:
#Test
void test() {
Mono<String> monoWithContent =
Mono.just("Content")
.map(element -> exceptionThrower());
// TEST 1
StepVerifier.create(monoWithContent)
.expectError()
.verify();
Mono<String> monoWithoutContent =
Mono.empty()
.map(element -> exceptionThrower());
// TEST 2
StepVerifier.create(monoWithoutContent)
.expectError()
.verify();
}
String exceptionThrower() {
throw new RuntimeException();
}
The result is :
TEST 1 - passes successfully, because the value is emitted from Mono and it is mapped to an exception (the RuntimeException thrown by the exceptionThrower().
TEST 2 - fails, because there is no value to be emitted from Mono, so the map method is not invoked and the whole execution finishes without an error.
So to summarize, if there is no content emitted from the Publisher, then the transformation operations are not invoked.
I don't have much experience with Mocking, I have recently started using it in my Junit test cases. However, I am having difficulties understanding the execution.
I am getting IllegalArgumentException when I try this code
PowerMockito.doNothing().when(spyObject, "lockUser", String.class, User.class);
But when I provide the values that the lockUser would recieve at the time of execution, everything works as expected.
Working code
PowerMockito.doNothing().when(spyObject, "lockUser", "my_text", userMock);
I am rather confused with this behavior. I was expecting identical behaviour.
Could someone explain why this is happening ?
In addition when I have the following code
PowerMockito.doNothing().when(spyObject, "lockUser", anyString(), anyObject());
The method is no longer mocked and the real method is invoked.
Interestingly I have another method with same name "lockUser" which takes different number of parameters. And in my other test method, I have used only Matchers (anyObject(), anyString() etc) and that works as expected.
PowerMockito.doNothing().when(spyObject, "lockUser", anyObject(), anyString(), anyString(), anyString());
All lockUser methods are priavate.
I am working with Mockito 1.9.5 together with PowerMock 1.5.6
Any help is greatly appreciated
Edit
Additional Code to make it clear
Class Core {
public Worker getWorker(String workerId) {
// Get worker from Map<String, Worker> fID_WRK with workerId as key
// Get user from worker (I have mocked this part, so my mock user is
// returned)
If(user.isTooOld()) {
lockUserAndNotify(reason, user);
throw new UserLockedException("Too old");
}
private void lockUserAndNotify(String reason, User user) {
lockUserAndNotify(reason, user.fname, user.lname); // locks user and notifies
}
public getUser(String login, String password) {
// find user in database
if(user password is too old) {
lockUserAndNotify(dbConnection, fname, lname, userId);
}
}
private lockUserAndNotify(Connection dbConn, String fName, String lName, String
userId) {
//method call to lock the user
//method call to notify the admin
}
}
My Test class
Class CoreTest {
#Test (expected = UserLockedException.class)
public void getUser_ThrowsException() throws
Exception{
Core core = new Core();
Core coreSpy = PowerMockito.spy(core);
when(userMock.isPwdUpdateTimeExpired()).thenReturn(true);
PowerMockito.doNothing().when(coreSpy, "lockUserAndNotify",
anyObject(), anyString(), anyString(), anyString(), anyString());
admin4.UserManager.getUser("l.user1","password");
}
#Test (expected = UserLockedException.class)
public void getWorker_ThrowsException() throws
Exception{
Core core = new Core();
Core coreSpy = PowerMockito.spy(core);
Map workerMap = Whitebox.getInternalState(coreSpy, "fID_WRK");
Map workerMapSpy = PowerMockito.spy(workerMap);
when(workerMapSpy.getWorker("12345")).thenReturn(workerMock);
when(workerMock.getUser()).thenReturn(userMock);
when(userMock.isTooOld()).thenReturn(true);
PowerMockito.doNothing().when(coreSpy, "lockUserAndNotify",
anyString(), anyObject());
admin4.UserManager.getWorker("123445");
}
}
So the test getUser_ThrowsException works as expected, but getWorker_ThrowsException does not.
To answer the part of your question about IllegalArgumentException: argument type mismatch, you get this because you're using the API incorrectly when you use
PowerMockito.doNothing().when(spyObject, "lockUser", String.class, User.class);
See the documentation of PowerMocktioStubber.when, relevant section reproduced here -
public static <T> org.mockito.stubbing.OngoingStubbing<T> when(Class<?> klass,
Object... arguments)
throws Exception
Expect calls to private static methods without having to specify the method name. The method will be looked up using the parameter types if possible
Throws:
Exception - If something unexpected goes wrong.
See Also:
Mockito#when(Object)}
As you've already observed you can use either the values of the real parameters or your can use Matchers like anyString.
Here's some sample code to demonstrate this -
public class Core {
public String getWorker(String workerId) {
if (workerId.isEmpty()) {
lockUser("Reason", workerId);
}
return workerId;
}
private void lockUser(String reason, String user) {
}
}
and the corresponding tests -
#RunWith(PowerMockRunner.class)
#PrepareForTest(Core.class)
public class CoreTest {
#Test
// this is incorrect usage and throws an IllegalArgumentException
public void test1() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", String.class, String.class);
spy.getWorker("");
}
#Test
public void test2() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", Mockito.anyString(), Mockito.anyString());
spy.getWorker("");
PowerMockito.verifyPrivate(spy).invoke("lockUser", Mockito.anyString(), Mockito.anyString());
}
#Test
public void test3() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", "abc", "Reason");
spy.getWorker("abc");
PowerMockito.verifyPrivate(spy, Mockito.times(0)).invoke("lockUser", Mockito.anyString(), Mockito.anyString());
}
}
Without compilable code or the exception that you get for getWorker_ThrowsException, it's not possible to answer why that doesn't work as expected. I can take a look again once you add the required information.
I am trying to write test cases for a function which return some data if validation passes else throws exception
private String validate(Test test) {
//Validation Logic which returns null or throws Exception
}
public Observable<Test> create(Test test) {
return Observable
.just(validate(test))
.flatMap(x -> testRepository
.create(test));
}
Test case for the same
#Test
public void Should_ThrowException_When_NoData() {
Test test = sampleTest();
TestSubscriber<Test> subscriber = new TestSubscriber<>();
testService
.create(test)
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
Throwable thrown = subscriber.getOnErrorEvents().get(0);
assertThat(thrown)
.isInstanceOf(CustomException.class)
.hasFieldOrPropertyWithValue("errorId", 102);
}
But the test case is failing on testService.create itself.
What is the problem here?
Thanks
It fails because you call validate() before its return value is used for creating the Observable. Instead, you can call fromCallable(() -> validate(test)) and get the execution of validate deferred.
We are using Testng 6.8.8 + Mockito 1.10.19 and, obviously we can't use MockitoJUnitRunner, but the validation framework still works!
In this thread I read that it should not be the case. Can someone explain? Is this because we still have #Before* callbacks and MockitoAnnotations.initMocks(this)?
My code:
public class MealTransformerTest {
MealTransformer mealTransformer = new MealTransformer();
#Test(expectedExceptions = NotImplementedException.class)
public void shouldThrowException() throws NotImplementedException {
mealTransformer.transform(any(),
any(),
any(),
any());
}
}
Nothing fails in this specific test, but when I run the suite, Mockito will tell me about incorrect use of matchers.
I can also do something like:
public class MealTransformerTest {
MealTransformer mealTransformer = new MealTransformer();
//I don't need it in the tests. But I need at least 1 #Mock or #Spy to trigger framework validation
#Mock
private CloneUtils cloneUtils;
#BeforeMethod
void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test(expectedExceptions = NotImplementedException.class)
public void shouldThrowException() throws NotImplementedException {
mealTransformer.transform(any(),
any(),
any(),
any());
}
#Test(expectedExceptions = NotImplementedException.class)
public void shouldThrowException123() throws NotImplementedException {
mealTransformer.transform(any(),
any(),
any(),
any());
}
}
I receive:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced argument matcher detected here:
....
Don't get me wrong, I really like how it works, but I was surprised to see it without #RunWith(MockitoJUnitRunner.class).
Matchers work via side-effects and static global state, so you can break this call into pieces to see what's happening.
MockitoAnnotations.initMocks(this);
// in #Before [1]
mealTransformer.transform(any(), any(), any(), any());
// [6] [2] [3] [4] [5]
After init [1], Java sees four calls to any [2-5] and one call to transform [6]. Mockito, however, only sees the four calls to any; Because mealTransformer is not a mock, Mockito can't see its calls. If you ran that test in isolation, Mockito would be left with four recorded matchers that are not consumed. The JVM would tear down the test framework, and the test would pass—unless you have a call to validateMockitoUsage in an #After method, which would catch exactly that case.
When you have two tests, however, they stack up like this:
MockitoAnnotations.initMocks(this);
// [1]
mealTransformer.transform(any(), any(), any(), any());
// [6] [2] [3] [4] [5]
// test passes! now the next test
MockitoAnnotations.initMocks(this);
// [7]
mealTransformer.transform(any(), any(), any(), any());
// [12] [8] [9] [10] [11]
Here, step 7 happens in the same test execution in the same JVM as steps 1-6, which means that initMocks is called when there are 4 unconsumed matchers on the stack. This should never happen, so initMocks takes its first opportunity to catch that error. One symptom would be if the misused matcher exception corresponds to a matcher outside of the test that fails: testB failing due to the misuse of a matcher in testA. With the use of validateMockitoUsage in an #After message, you'd have the appropriate test fail instead.
Im trying to make a simple as a can example which could be found on official PowerMock's page (here).I' doing a partial mock of this class :
public class Simple {
public String doMe() {
return privateMethod();
}
private String privateMethod() {
return "POWERMOCK sucks";
}
}
And wrote a simple test class :
#RunWith(PowerMockRunner.class)
#PrepareForTest(Simple.class)
public class ProcessorTest {
#Test
public void doMe() throws Exception {
Simple spy = PowerMockito.spy(new Simple());
PowerMockito.doReturn("hello").when(spy, "privateMethod");
String res = spy.doMe();
PowerMockito.verifyPrivate(spy, Mockito.times(1000)).invoke(
"privateMethod");
Assert.assertEquals( res, "hello");
}
}
But result is like this :
java.lang.AssertionError: expected [hello] but found [null]
Expected :hello
Actual :null
<Click to see difference>
at org.testng.Assert.fail(Assert.java:94)
So Powermock not only fails to mock the privateMethod and return 'null' it's OK with that it was called 1000 times when it was not.
It get even more creepy if I try to mess with mocking like this :
PowerMockito.doReturn(1).when(spy, "privateMethod");
So I'm trying to return an Integer instead of String from the privateMethod.
Then I get this :
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Integer cannot be returned by doMe()
doMe() should return String
***
So by some reason Powermock is trying to mock public doMe method.
Any one understands what is happining? I dont.
Thanks.
My environment is :
Java 1.8, Mockito 1.10.19, Powermock 1.6.2
Ok, I found solution, the problem was that JUnit's #RunWith did not actually do the trick so I had to extend from PowerMockTestCase to make it work. The test looks like this now and it works like a charm:
#PrepareForTest(Simple.class)
public class ProcessorTest extends PowerMockTestCase {
#Test
public void doMe() throws Exception {
Simple spy = PowerMockito.spy(new Simple());
PowerMockito.doReturn("hello").when(spy, "privateMethod");
String res = spy.doMe();
PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke(
"privateMethod");
Assert.assertEquals( res, "hello");
}
}