how to mock static class function with inner method in mockito? - java

I have a class name HibernateSessionManager which have static method
public static HibernateSessionManager current;
I trying to mock
public Mbc_session getMBCSessionByGuid(String sessionGuid) {
try {
return HibernateSessionManager.current.withSession(hibernateSession -> {
return hibernateSession.get(Mbc_session.class, sessionGuid);
});
}
catch (Exception e) {
logger.error().logFormattedMessage(Constants.MBC_SESSION_GET_ERROR_STRING,
e.getMessage()); throw new DAOException(ErrorCode.MBC_1510.getCode(), ErrorCode.MBC_1510.getErrorMessage() + ",Operation: getMBCSessionByGuid");
}
}
i am using following function in #before
public static void initMocks(Session session) {
HibernateSessionManager.current = mock(HibernateSessionManager.class,Mockito.RETURNS_DEEP_STUBS);
HibernateTransactionManager.current = mock(HibernateTransactionManager.class,Mockito.RETURNS_DEEP_STUBS);
doCallRealMethod().when(HibernateTransactionManager.current).withTransaction(any(), any());
doCallRealMethod().when(HibernateSessionManager.current).withSession(any(Consumer.class));
// Mockito.when(HibernateSessionManager.current.withSession((Consumer<Session>) any(Function.class))).thenCallRealMethod();
when(HibernateSessionManager.current.getSession()).thenReturn(session);
}
My test case is following
#Test public void test_getMBCSessionByGuid() {
Mbc_session mbcSession = new Mbc_session();
String sessionGuid = "session GUID";
when(HibernateSessionManager.current.getSession()).thenReturn(session);
// when(sessionFactory.getCurrentSession()).thenReturn(session);
when(session.get(Mbc_session.class, sessionGuid)).thenReturn(mbcSession);
Mbc_session mbcSession2 = mbc_sessionDao.getMBCSessionByGuid(sessionGuid);
assertNull(mbcSession2);
}
it passed but coverage is not touching following code
return hibernateSession.get(Mbc_session.class, sessionGuid);
here is my withSession code
public void withSession(Consumer<Session> task) {
Session hibernateSession = getSession();
try {
task.accept(hibernateSession);
} finally {
HibernateSessionManager.current.closeSession(hibernateSession);
}
}
openSession
public Session getSession() {
Session threadCachedSession = threadSession.get();
if (threadCachedSession != null) {
if (!threadCachedSession.isOpen()) { throw new
IllegalStateException("Session closed outside of
HibernateSessionManager.");
}
return threadCachedSession;
} return sessionFactory.openSession();
}

Looking at the code and assuming it compiles, I believe the problem is that you have two withSession(...) methods and in the code posted you are trying to mock the wrong one. Here are their signatures:
// You should NOT mock this one
void withSession(Consumer<Session> task) {
...
}
// You should mock this one instead
Mbc_session withSession(Function<Session, Mbc_session> task) {
...
}
It was easy to guess as the getMBCSessionByGuid method contains the snippet below with the Function<Session, Mbc_session> being passed as an argument to withSession(...) instead of Consumer<Session>:
return HibernateSessionManager.current.withSession(hibernateSession -> {
// something is returned which means a Function is passed, not a Consumer
return hibernateSession.get(Mbc_session.class, sessionGuid);
});
As an easy fix, you can just add the following to the test:
doCallRealMethod().when(HibernateSessionManager.current).withSession(any(Function.class));
and remove the existing mock configuration with a Consumer:
doCallRealMethod().when(HibernateSessionManager.current).withSession(any(Consumer.class));
P.S. Just in case, I can easily reproduce the issue on my machine.

Related

Getting "Wanted but not invoked" when running unit test

Trying to test repository method, but my test fails with following "Wanted but not invoked: cellphonesDao.deleteAllCellphones();"
Here is repo method:
#Override
public Single<Cellphone[]> getCellphones() {
Single<CellPhoneEntity[]> remoteCellphones =
networkModule.productApi()
.getCellPhones()
.onErrorResumeNext(cellphonesDao.getAllCellphones()); // todo return value if true
Single<CellPhoneEntity[]> localCellphones = cellphonesDao.getAllCellphones();
return Single.zip(remoteCellphones, localCellphones, (remote, local) -> {
if (!Arrays.equals(remote, local)) {
cellphonesDao.deleteAllCellphones();
for (CellPhoneEntity cellPhoneEntity : remote) {
cellphonesDao.insertCellphone(cellPhoneEntity);
}
}
return mapper.toCellphones(remote);
});
}
Main porpuse is to test repo method in correct way. Guess the way I chose is not good.
Here is test implementation:
class CellPhoneRepositoryImplTest {
NetworkModule networkModule;
CellphonesDao cellphonesDao;
CellphoneMapper cellphoneMapper;
CellPhoneRepositoryImpl cellPhoneRepository;
ProductAPI productAPI;
#BeforeEach
void setUp() {
networkModule = Mockito.mock(NetworkModule.class);
cellphonesDao = Mockito.mock(CellphonesDao.class);
productAPI = Mockito.mock(ProductAPI.class);
cellphoneMapper = new CellphoneMapper();
cellPhoneRepository = Mockito.spy(new CellPhoneRepositoryImpl(
networkModule,
cellphonesDao,
cellphoneMapper
));
}
#Test
void whenRemoteDataAreDifferentFromLocalDbIsUpdated() {
int numberOfCellphones = 5;
CellPhoneEntity[] remoteCellphones = DummyCellphoneEntityFactory.generateCellphones(numberOfCellphones);
CellPhoneEntity[] localCellphones = DummyCellphoneEntityFactory.generateCellphones(numberOfCellphones);
Mockito.when(networkModule.productApi()).thenReturn(productAPI);
Mockito.when(networkModule.productApi().getCellPhones()).thenReturn(wrapWithSingle(remoteCellphones));
// Mockito.when(networkModule.productApi().getCellPhones().onErrorResumeNext(cellphonesDao.getAllCellphones())).thenReturn(wrapWithSingle(remoteCellphones));
Mockito.when(cellphonesDao.getAllCellphones()).thenReturn(wrapWithSingle(localCellphones));
Mockito.doNothing().when(cellphonesDao).deleteAllCellphones();
cellPhoneRepository.getCellphones();
Mockito.verify(cellphonesDao, Mockito.times(1))
.deleteAllCellphones();
}
private Single<CellPhoneEntity[]> wrapWithSingle(CellPhoneEntity[] cellphones) {
return Single.just(cellphones);
}
}
I will be glad for any suggestion)
The code inside the returned Single isn't executed immediately, but your verifications are. Try calling cellPhoneRepository.getCellphones().blockingGet() instead of just cellPhoneRepository.getCellphones(). The blockingGet() should make your test wait until the Single is done executing.

How do i create unit test for a client service with void methods?

I want to create a unit test for a client service.
The function of the client service is to call the webservice, get data, and update the database as scheduled.
The scheduled method return void.
How to create unit test for a
client service
schedule method
void returning methods
The client is like this:
#ApplicationScoped
public class ClientClass {
private static final Logger LOGGER = Logger.getLogger(VdsClient.class);
#Inject
Client client;
VMR vmr;
CommandService commandService;
public VdsClient(VMR vmr,
CommandService commandService) {
this.vmr = vmr;
this.commandService = commandService;
}
#Scheduled(XXX)
public void getVal() {
var monitoringStateFilter =
new VMF.vmf(true, true);
var monoResultList =
vmr.fvms(monitoringStateFilter)
.collectList();
if (monoResultList != null) {
var resultList = monoResultList.block();
if (resultList != null) {
resultList.stream()
.map(row -> row.getValue("val", val.class))
.map(vin -> this.updateEstimate(val.getValue()))
}
}
}
public Tuple2<String, Boolean> updateEstimate(String val) {
List<route> routeList;
try {
routeList = vdsClient.getval(val)
.getItem();
boolean hasDealerDestination = false;
for (Route route : routeList) {
if (vd.DestLocationType._00.value()
.equals(route.getTransportConnectionPointTyp())) {
hasDealerDestination = true;
var estimate = DateTimeUtil.convertToInstantWithOffset(route.getArrivalDate(),
route.getArrivalTime(), route.getTimezone(), DateTimeUtil.PATTERN_LONG_DATE);
if (estimate == null) {
return Tuples.of(val, false);
}
var result = this.updateVehicleEstimate(val, estimate);
return Tuples.of(val, result);
}
}
if (!hasDealerDestination) {
return Tuples.of(val, false);
} else {
return Tuples.of(val, false);
}
} catch (route e) {
return Tuples.of(val, false);
} catch (Exception e) {
return Tuples.of(val, false);
}
}
public Boolean updateVehicleEstimate(String val, Instant estimate) {
var vehicleUpdate = vu.vuc.builder()
.val(new Val(val))
.Estimate(estimate)
.build();
return (Boolean) cs.ec(vu).block();
}
A unit should only be testing that a particular unit of code is working fine. In your case, for the unit test, you should assume that the webservice will return the data and the db updation works fine. We can accomplish this through mocking the response for each of these calls.
For void returning methods, you can actually verify if the call was indeed made or not.
For example:
Mockito.verify(mockedObject, Mockito.times(1)).callWebService(mockedParameter1, mockedParameter2);
There is another way, though I personally don't prefer that:
You can declare a class variable and make sure the value updates itself whenever the scheduled method reaches the end of the code. Read that value in your test and assert on its value. If the value is updated, then your code worked fine, else NO and it's a failure.
Also, in case you want to actually make sure the webservice returned the correct response / db entry was updated, then those should be part of integration tests and not unit tests.

Testing method having CompletableFuture.allOf using mockito

I have a method called doParallelThings:
public Dummy doParallelThings(Map<String, String> mapp) throws Exception {
Dummy dummy = new Dummy();
CompletableFuture<Ans1> one = firstService.getOne(mapp.get("some1"), mapp);
CompletableFuture<Ans2> two = secondService.getTwo(headersMap.get("some2"), mapp);
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(one, two);
try {
combinedFuture.get();
dummy.setOne(one.get());
dummy.setTwp(two.get());
} catch (Throwable e) {
}
return dummy;
}
Code works fine but when I'm trying to test it,
combinedFuture.get(); goes to infinite loop.
Unit test is as below:
#Mock
private CompletableFuture<Void> ans;
#Test
public void testDoParallelThings() throws Exception {
PowerMockito.mockStatic(CompletableFuture.class);
PowerMockito.when(CompletableFuture.allOf(any())).thenReturn(ans);
when(ans.get()).thenReturn(null);
Dummy dummy = dummyService. doParallelThings(mockMap);
assertNotNull(dummy);
}
I have also added #RunWith(PowerMockRunner.class)
#PrepareForTest({CompletableFuture.class}) above the test class.
What am I missing?
when(firstService.getOne(any(), any())).thenReturn(CompletableFuture.completedFuture(mockOne));
solved my problem

How can I test exception in completable future?

I have been converting some code to be asynchronous. The original unit test used the annotation #Test(expected = MyExcpetion.class) but I don't think this will work because the exception I want to assert on is wrapped in java.util.concurrent.ExcutionException . I did try calling my future like this but my assertion is still failing and I don't love that I had to add in return null
myApiCall.get(123).exceptionally((ex) -> {
assertEquals(ex.getCause(),MyCustomException.class)
return null
}
I also tried this flavor but still not working
myApiCall.get(123).exceptionally((ex) -> {
assertThat(ex.getCause())
.isInstanceOF(MyException.class)
.hasMessage("expected message etc")
return null;
}
My API just throws exception if it can't find id. How should I be properly testing this? Can I use that original annotation in anyway?
my api call reaches out to db when run. In this test I am setting up my future to return an error so it doesn't actually try to communicate with anything. the code under test looks like this
public class myApiCall {
public completableFuture get(final String id){
return myService.getFromDB(id)
.thenApply(
//code here looks at result and if happy path then returns it after
//doing some transformation
//otherwise it throws exception
)
}
}
in the unit test I force myService.getFromDB(id) to return bad data so I can test exception and also keep this a unit test don't reach out to db etc.
Let's assume your API throws if called with 0:
public static CompletableFuture<Integer> apiCall(int id) {
return CompletableFuture.supplyAsync(() -> {
if (id == 0) throw new RuntimeException("Please not 0!!");
else return id;
});
}
You can test that it works as expected with the following code (I'm using TestNG but I suspect it won't be too difficult to translate into a JUnit test):
#Test public void test_ok() throws Exception {
CompletableFuture<Integer> result = apiCall(1);
assertEquals(result.get(), (Integer) 1);
}
#Test(expectedExceptions = ExecutionException.class,
expectedExceptionsMessageRegExp = ".*RuntimeException.*Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
result.get();
}
Note that the second test uses the fact that the ExecutionException message will contain the original exception type and message and captures the expectation with a regex. If you can't do that with JUnit, you can call result.get() in a try/catch block and call throw e.getCause(); in the catch block. In other words, something like this:
#Test(expectedExceptions = RuntimeException.class,
expectedExceptionsMessageRegExp = "Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
try {
result.get();
} catch (ExecutionException e) {
throw e.getCause();
}
}
You can try also alternative option:
import org.hamcrest.core.IsInstanceOf;
import org.junit.rules.ExpectedException;
public class Test() {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void myApiCallTest() {
thrown.expect(ExcutionException.class);
thrown.expectCause(IsInstanceOf.instanceOf(MyException.class));
thrown.expectMessage("the message you expected");
myApiCall.get("");
}
}
Assuming that:
public class myApiCall {
public completableFuture get(final String id) {
// ...
throw new ExcutionException(new MyException("the message you expected"))
}
}
Assume that you have a class and you want to test a method which returns a completable future:
public class A {
private final Api api;
public A(Api api) { this.api = api;}
public CompletableFuture<Void> execute(Integer input) {
final CompletableFuture<Void> future = api.execute(input)
.thenApplyAsync(result -> doSomething())
.exceptionally(ex -> doFailure());
return future;
}
}
To test the execution of "doSomething()" then you may use mockito and do the following:
// prepare test
final Api api = mock(Api.class)
final A a = new A(api);
when(api.execute(any(Integer.class)))
.thenReturn(CompletableFuture.completedFuture(null));
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
...
To test "doFailure" do the following:
when(api.execute(any(Integer.class))).thenAnswer(answer -> {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
return future;
});
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
assertTrue(result.isCompletedExceptionally());
that is easy thing doing in junit-4. Are you remember the #RunWith annotation? Yes, write your own TestRunner to intercept the exception before the junit expected exception processor is invoked, for example:
public class ConcurrentRunner extends BlockJUnit4ClassRunner {
public ConcurrentRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected Statement possiblyExpectingExceptions(FrameworkMethod method,
Object test,
Statement next) {
return super.possiblyExpectingExceptions(
method, test, throwingActualException(next)
);
}
private Statement throwingActualException(Statement next) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
next.evaluate();
} catch (ExecutionException | CompletionException source) {
throw theActualExceptionOf(source);
}
}
private Throwable theActualExceptionOf(Exception source) {
return source.getCause() != null ? source.getCause() : source;
}
};
}
}
just annotated with #RunWith(ConcurrentRunner.class) on the test, you needn't change your test code at all. for example:
#RunWith(ConcurrentRunner.class)
public class ConcurrentExpectedExceptionTest {
#Test(expected = IllegalArgumentException.class)
public void caughtTheActualException() throws Throwable {
myApiCall().join();
}
private CompletableFuture<Object> myApiCall() {
return CompletableFuture.supplyAsync(() -> {
throw new IllegalArgumentException();
});
}
}

How to call a method from another method within same class in java

I have two methods in the same class, the first method isgetEventByEventId and the second method is addEventUserRealtionMapping. I need to call the getEventByEventId method from the addEventUserRelationMapping method. How can I get that done?
public EventBO getEventByEventId(long eventId) throws UserServiceException {
try {
EventDO eventDO = eventDAOImpl.getEventByEventId(eventId);
EventBO eventBO = mapper.mapEventDOToBO(eventDO, new EventBO());
return eventBO;
} catch (UserDataException uExp) {
throw new UserServiceException("Error while getting event for event id " + eventId, uExp);
}
}
public int addEventUserRealtionMapping(ArrayList<UserBO> userBOs, long eventId) throws UserServiceException {
List<EventUserRelationDO> totalAddedCount;
ArrayList<UserDO> userDOs = new ArrayList<>();
try {
for (UserBO userBO : userBOs) {
UserDO userDO = mapper.mapUserBOToDO(userBO, new UserDO());
userDOs.add(userDO);
}
EventBO eventBO =new EventBO();
eventBO =getEventByEventId(eventId);//I am try that while call method1 but it doesn't work
MessageBO messageBO = new MessageBO();
messageBO.setEventId(eventBO.getEventId());
messageBO.setEventTitle(eventBO.getText());
messageBO.setMessage(eventBO.getText());
messageBO.setRingeeUserId(eventBO.getRingeeUserId());
messageBO.setMessageType(IRingeeConstants.MESSAGE_TYPE_INVITATION);
totalAddedCount = eventDAOImpl.addEventUserRelationMapping(userDOs, eventId);
if (totalAddedCount.size() == userDOs.size()) {
manageMessageService.sendMessageToGroup(userBOs, messageBO);
}
} catch (UserDataException dExp) {
throw new UserServiceException(" exception while adding user relationship for eventId " + eventId, dExp);
}
return totalAddedCount.size();
}
You can call it using this.methodName() or directly by writing the methodName()
class ClassName{
public void method1(){
}
public void method2(){
this.method1(); // called the first method of the same class
}
}
You can call function easily but you will need to put getEventByEventId inside try catch or throw UserServiceException form addEventUserRealtionMapping
if you have infinite loop it seem that you mapEventDOToBO calls addEventUserRealtionMapping inside it and you are try getEventByEventId again so that it causes infinite loop you

Categories

Resources