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.
Related
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.
I have to unit test the below method, whereas all the lines of this code related to third party aws library. The method also returns nothing. So only test I can do is verifying the exception. Any other test can I do to improve the code coverage?
public void multipartUpload() throws InterruptedException {
TransferManager tm = TransferManagerBuilder.standard()
.withS3Client(s3Client)
.withMultipartUploadThreshold(1024l)
.build();
PutObjectRequest request = new PutObjectRequest(bucketName, keyName, filePath);
Upload upload = tm.upload(request);
upload.waitForCompletion();
}
Let see the code that needs to be tested:
public class DemoCodeCoverage {
public void showDemo(LibraryCode library) {
System.out.println("Hello World!");
library.runDemoApplication();
// Extract the below code to a method since LibraryCode is not passed
// Then ignore running that method
// LibraryCode library = new LibraryCode()
// library.runDemoApplication_1();
// library.runDemoApplication_2();
// library.runDemoApplication_3();
System.out.println("World ends here!");
}
public boolean showBranchingDemo(boolean signal) {
if (signal) {
signalShown();
} else {
noSignal();
}
return signal;
}
public void signalShown() {
System.out.println("signalShown!");
}
public void noSignal() {
System.out.println("NoSignal!");
}
}
public class LibraryCode {
// Library can be AWS/Database code which needs authentication
// And this authentication is not a concern for our UT
// Still will end up execption when we do our UT
public void runDemoApplication() {
throw new RuntimeException();
}
}
Below can give good code coverage:
public class DemoCodeCoverageTest {
#Test
public void testShowDemo() {
DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
LibraryCode lib = Mockito.mock(LibraryCode.class);
Mockito.doNothing().when(lib).runDemoApplication();
t.showDemo(lib);
// when(bloMock.doSomeStuff()).thenReturn(1);
// doReturn(1).when(bloMock).doSomeStuff();
}
#Test
public void testShowBranchingDemo() {
DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
assertEquals(true, t.showBranchingDemo(true));
assertEquals(false, t.showBranchingDemo(false));
}
#Test
public void testSignalShown() {
DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
t.showBranchingDemo(true);
Mockito.verify(t, times(1)).signalShown();
}
#Test
public void testNoSignal() {
DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
t.showBranchingDemo(false);
Mockito.verify(t, times(1)).noSignal();
}
}
Below are the steps to increase the test code coverage:
Case_1: Testing void method
Assume you have method the does not take any params and return nothing.
public void printHelloWorld() {
System.out.println("Hello World")
}
Still you can write test that calls this method and returns successfully without any runtimeException.
Actually we haven't tested anything here other than giving a option to run the code by our tests. Thus increase the code coverage.
Additionally you can verify the invocation:
Mockito.verify(instance, times(1)).printHelloWorld();
There are circumstances you cannot test those, example say it is third party library call, then the library might have tested already, we just need to run through it.
#Test
public void testPrintHelloWorld() {
// may be hibernate call/other 3rd party method call
instance.printHelloWorld();
}
If your tool is not strict for 100% code coverage, you can even ignore it and justify it.
Case_2: Testing a method with object created and called another method inside the testing method
Assume you have method the does call DB to add entry in Hello_World table also prints it in console like below.
public void printHelloWorld() throws DBException {
DBConnection db = new DBConnection();
db.createEntry(TABLE_NAME, "Hello World");
System.out.println("Hello World")
}
You can extract those db code into new method, then test it separately.
public void printHelloWorld() throws DBException {
makeHelloWorldEntryInTable();
System.out.println("Hello World")
}
public void makeHelloWorldEntryInTable() throws DBException {
DBConnection db = new DBConnection();
db.createEntry(TABLE_NAME, "Hello World");
}
While testing with DB you would expect the DBConnectionException as it is just unit test. So one test with #Test(expected=DBException) for makeHelloWorldEntryInTable, and another test on printHelloWorld() with skipping the method makeHelloWorldEntryInTable call like below. Thus increases the code coverage.
#Test(expected=DBException)
public void testMakeHelloWorldEntryInTable() {
//This can any third party library which cannot be configured for ut.
//One example is testing the AWS bucket exist or not.
instance.makeHelloWorldEntryInTable();
}
#Test
public void testPrintHelloWorld() {
Mockito.doNothing()
.when(localInstance)
.makeHelloWorldEntryInTable();
localInstance.printHelloWorld();
}
Case_3: if you have private method, then make it default package level and test it. Thus improves the code coverage.
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.
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
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();
});
}
}