I have the following code snippet from a unit test using Mockito which has happily been passing for months/years.
#Test
public void testAddRemoveTarFile() throws IOException, GeneralSecurityException {
//add a TAR file
TableRowCount downloadRowCount = new TableRowCount(tableDownloads);
//create the item that will appear in the table row
MyHSAItem item = createMyHSAItem();
Mockito.when(model.getConfigurations(Type.TAR)).thenReturn(Arrays.asList(item));
//get the table model
JTable downloadsTable = (JTable)UI.findComponent(getPanel(), "download");
final MyHSATableModel tableModel = (MyHSATableModel ) downloadsTable.getModel();
final MyHSAEvent event = Mockito.mock(MyHSAEvent.class);
Mockito.when(event.getType()).thenReturn(MyHSAEvent.Type.MODEL);
//Fire table event when adding observation
final File xmlFile = Mockito.mock(File.class);
Mockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
tableModel.modelChanged(event);
return null;
}
}).when(model).addObservation(xmlFile);
//Fire table event when deleting observation
Mockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
tableModel.modelChanged(event);
return null;
}
}).when(model).delete(item, true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
UI.findButtonWithText(getPanel(), "Add ...").doClick();
}
});
//select a file, table row should update
chooseFile(xmlFile);
ensureEquals(1, downloadRowCount, TIMEOUT);
// Remove download + cancel
UI.leftClick(tableDownloads);
clickRemove("Cancel");
ensureEquals(1, downloadRowCount, TIMEOUT);
// Remove download + OK
UI.leftClick(tableDownloads);
Mockito.when(model.getConfigurations(Type.TAR)).thenReturn(new ArrayList<MyHSAItem>());
clickRemove("OK");
ensureEquals(0, downloadRowCount, TIMEOUT);
}
Suddenly it failed just once with:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at herschel.ia.pal.pool.hsa.gui.MyHsaPreferencePanelTest.testAddRemoveTarFile(MyHsaPreferencePanelTest.java:257)
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. although stubbed methods may return mocks, you cannot inline mock creation (mock()) call inside a thenReturn method (see issue 53)
I understand this error but not how it can randomly happen. The Mockito.doAnswer seems to be the problem. I am not inlining mocks and it seems to be ok and has always worked. What can it be?
Line 257 stars with
Mockito.doAnswer(new Answer<Void>() {
model is indeed a field initialised like so:
#Mock
private MyHSANotifiableModelImpl model;
public void setUpPanel() {
MockitoAnnotations.initMocks(this);
Both the answers return null and have signature Void, so not sure what you mean exactly.
Thanks for any help
Related
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 have an HTTPClient test for my spring boot app. I have a class that throws an exception if the a POST request to the server is in a string 2048 bytes or over.
#Component
public class ApplicationRequestSizeLimitFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println(request.getContentLength());
if (request.getContentLengthLong() >= 2048) {
throw new IOException("Request content exceeded limit of 2048 bytes");
}
filterChain.doFilter(request, response);
}
}
I created a unit test for it but I am not sure how I can write an assert statement to check if it fails to post the request.
Right now I have this so far in my test class
#Test
public void testSize() throws ClientProtocolException, IOException {
Random r = new Random(123);
long start = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 65536; i++)
s += r.nextInt(2);
String result = Request.Post(mockAddress)
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(s, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
}
This test fails which is what I want but I want to create an assert so it passes (assert that it fails the http response due to being over the byte limit).
You can surround the failing part with a try/catch, and call fail() at the end of the try block. If an exception is thrown, the fail() instruction should not be reached, and your test should pass.
#Test has an argument to assert that a particular exception gets thrown, you could write your test like e.g :
#Test(expected = IOException.class)
public void testSize() throws ClientProtocolException, IOException {
...
}
There are 3 ways you can achieve that:
1) Use #Test(expected = ....) annotation where you provide class of exception you want to check.
#Test(expected = IOException.class)
public void test() {
//... your test logic
}
This is not a recommended way of exception testing unless your test is really really small and does one thing only. Otherwise, you may get an IOException thrown but you won't be sure which part of test code exactly caused it.
2) Use #Rule annotation with ExpectedException class:
#Rule
public ExpectedException exceptionRule = ExpectedException.none();
#Test
public void testExpectedException() {
exceptionRule.expect(IOException.class);
exceptionRule.expectMessage("Request too big.");
//... rest of your test logic here
}
Please note that exceptionRule has to be public.
3) And last one, quite old-fashioned way:
#Test
public void test() {
try {
// your test logic
fail(); // if we get to that point it means that exception was not thrown, therefore test should fail.
} catch (IOException e) {
// if we get here, test is successfull and code seems to be ok.
}
}
It's an old fashioned way that adds some unnecessary code to your test that is supposed to be clean.
There is another solution, not already presented in these answers, and is my personal preference. assertThatThrownBy
in your case
#Test
public void testSizeException(){
assertThatThrownBy(()-> Request.Post(mockAddress)
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(s, ContentType.TEXT_PLAIN)
.execute().returnContent().asString())
.isInstanceOf(IOException.class)
.hasMessageContaining("Request content exceeded limit of 2048
bytes");
}
*Disclaimer, above code written directly into SO editor
I am trying to figure out how to determine if all async HTTP GET requests I've made have completed, so that I can execute another method. For context, I have something similar to the code below:
public void init() throws IOException {
Map<String, CustomObject> mapOfObjects = new HashMap<String, CustomObject>();
ObjectMapper mapper = new ObjectMapper();
// some code to populate the map
mapOfObjects.forEach((k,v) -> {
HttpClient.asyncGet("https://fakeurl1.com/item/" + k, createCustomCallbackOne(k, mapper));
// HttpClient is just a wrapper class for your standard OkHTTP3 calls,
// e.g. client.newcall(request).enqueue(callback);
HttpClient.asyncGet("https://fakeurl2.com/item/" + k, createCustomCallbackTwo(k, mapper));
});
}
private createCustomCallbackOne(String id, ObjectMapper mapper) {
return new Callback() {
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try (ResponseBody body = response.body()) {
CustomObject co = mapOfObjects.get(id);
if (co != null) {
co.setFieldOne(mapper.readValue(body.byteStream(), FieldOne.class)));
}
} // implicitly closes the response body
}
}
#Override
public void onFailure(Call call, IOException e) {
// log error
}
}
}
// createCustomCallbackTwo does more or less the same thing,
// just sets a different field and then performs another
// async GET in order to set an additional field
So what would be the best/correct way to monitor all these asynchronous calls to ensure they have completed and I can go about performing another method on the Objects stored inside the map?
The most simple way would be to keep a count of how many requests are 'in flight'. Increment it for each request enqueued, decrement it at the end of the callback. When/if the count is 0, any/all requests are done. Using a semaphore or counting lock you can wait for it to become 0 without polling.
Note that the callbacks run on separate threads, so you must provide some kind of synchronization.
If you want to create a new callback for every request, you could use something like this:
public class WaitableCallback implements Callback {
private boolean done;
private IOException exception;
private final Object[] signal = new Object[0];
#Override
public void onResponse(Call call, Response response) throws IOException {
...
synchronized (this.signal) {
done = true;
signal.notifyAll();
}
}
#Override
public void onFailure(Call call, IOException e) {
synchronized (signal) {
done = true;
exception = e;
signal.notifyAll();
}
}
public void waitUntilDone() throws InterruptedException {
synchronized (this.signal) {
while (!this.done) {
this.signal.wait();
}
}
}
public boolean isDone() {
synchronized (this.signal) {
return this.done;
}
}
public IOException getException() {
synchronized (this.signal) {
return exception;
}
}
}
Create an instance for every request and put it into e.g. a List<WaitableCallback> pendingRequests.
Then you can just wait for all requests to be done:
for ( WaitableCallback cb : pendingRequests ) {
cb.waitUntilDone();
}
// At this point, all requests have been processed.
However, you probably should not create a new identical callback object for every request. Callback's methods get the Call passed as parameter so that the code can examine it to figure out which request it is processing; and in your case, it seems you don't even need that. So use a single Callback instance for the requests that should be handled identically.
If the function asyncGet calls your function createCustomCallbackOne then its easy.
For each key you are calling two pages. "https://fakeurl1.com/item/" and "https://fakeurl2.com/item/" (left out + k)
So you need a map to trach that and just one call back function is enough.
Use a map with key indicating each call:
static final Map<String, Integer> trackerOfAsyncCalls = new HashMap<>();
public void init() throws IOException {
Map<String, CustomObject> mapOfObjects = new HashMap<String, CustomObject>();
//need to keep a track of the keys in some object
ObjectMapper mapper = new ObjectMapper();
trackerOfAsyncCalls.clear();
// some code to populate the map
mapOfObjects.forEach((k,v) -> {
HttpClient.asyncGet("https://fakeurl1.com/item/" + k, createCustomCallback(k,1 , mapper));
// HttpClient is just a wrapper class for your standard OkHTTP3 calls,
// e.g. client.newcall(request).enqueue(callback);
HttpClient.asyncGet("https://fakeurl2.com/item/" + k, createCustomCallback(k, 2, mapper));
trackerOfAsyncCalls.put(k + "-2", null);
});
}
//final important
private createCustomCallbackOne(final String idOuter, int which, ObjectMapper mapper) {
return new Callback() {
final String myId = idOuter + "-" + which;
trackerOfAsyncCalls.put(myId, null);
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
trackerOfAsyncCalls.put(myId, 1);
///or put outside of if if u dont care if success or fail or partial...
Now set up a thread or best a schduler that is caclled every 5 seconds, check all eys in mapOfObjects and trackerOfAsyncCalls to see if all keys have been started and some final success or timeout or error status has been got for all.
I have following method:
#Component
public class WriteCsvToResponse {
private static final Logger LOGGER = LoggerFactory.getLogger(WriteCsvToResponse.class);
public void writeStatus(PrintWriter writer, Status status) {
try {
ColumnPositionMappingStrategy mapStrategy
= new ColumnPositionMappingStrategy();
mapStrategy.setType(Status.class);
String[] columns = new String[]{"id", "storeId", "status"};
mapStrategy.setColumnMapping(columns);
StatefulBeanToCsv btcsv = new StatefulBeanToCsvBuilder(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.withMappingStrategy(mapStrategy)
.withSeparator(',')
.build();
btcsv.write(status);
} catch (CsvException ex) {
LOGGER.error("Error mapping Bean to CSV", ex);
}
}
I have no idea how to test it properly using mockito.
Use it to wrap the object status into csv format.
I used StringWriter to wrap the response in it.
There are no more details left, but it seems I have to create some words to pass the validation :)
You do not need mockito to test this method, only a java.io.StringWriter.
Here is how you can write the test for a nominal use:
#Test
void status_written_in_csv_format() {
// Setup
WriteCsvToResponse objectUnderTest = new WriteCsvToResponse ();
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
// Given
Status status = ...
// When
objectUnderTest.writeStatus(printWriter, status);
// Then
String actualCsv = stringWriter.toString();
assertThat(actualCsv.split("\n"))
.as("Produced CSV")
.containsExactly(
"id,storeId,status",
"42,142,OK");
}
This example assume some things about your Status object, but you have the general idea.
For assertions, I use AssertJ, but you can do the same with JUnit5 built-in assertions.
Hope this helps !
With a bit of a refactoring, where the Builder is a Spring Bean injected into this component.
You can then mock that builder to return a mocked StatefulBeanToCsv, specifically the write method, where you write the conditions and assertions. If you encounter an error, you throw some unchecked exception, like IllegalStateException, if everything is alright, you don't throw anything
you can write a test like this and change your input in write method:
#Test
public void test() {
WriteCsvToResponse writeCsvToResponse = mock(WriteCsvToResponse.class);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
write((Status)args[1]);
return null;
}
}).when(writeCsvToResponse).writeStatus(any(PrintWriter.class),any(Status.class));
writeCsvToResponse.writeStatus(writer, status);
}
public void write(Status status) {
// do anythings you like with status
}
when I was sync I wrote unit tests mocking the persistence part and check the caller's behavior. Here is an example about what I usually did:
#Mock
private OfferPersistenceServiceImpl persistenceService;
#Inject
#InjectMocks
private OfferServiceImpl offerService;
...
#Test
public void createInvalidOffer() {
offer = new Offer(null, null, null, null, null, 4, 200D, 90D);
String expectedMessage = Offer.class.getName() + " is not valid: " + offer.toString();
Mockito.when(persistenceService.create(offer)).thenThrow(new IllegalArgumentException(expectedMessage));
Response response = offerService.create(offer);
Mockito.verify(persistenceService, Mockito.times(1)).create(offer);
Assert.assertEquals(INVALID_INPUT, response.getStatus());
String actualMessage = response.getEntity().toString();
Assert.assertEquals(expectedMessage, actualMessage);
}
But now I fell in love with Vertx.io (to which I am pretty new) and I want to be async. Nice. But Vertx has handlers, so the new persistence component to mock looks like this:
...
mongoClient.insert(COLLECTION, offer, h-> {
...
});
So I am guessing how to mock handler h to tests class who's using that mongoClient or even if it is the right way to test with Vertx.io. I am using vertx.io 3.5.0, junit 4.12 and mockito 2.13.0. Thanks.
Update
I tried to follow tsegimond suggestion but I can't get how Mockito's Answer and ArgumentCaptor can help me. Here is what I tried so far.
Using ArgumentCaptor:
JsonObject offer = Mockito.mock(JsonObject.class);
Mockito.when(msg.body()).thenReturn(offer);
Mockito.doNothing().when(offerMongo).validate(offer);
RuntimeException rex = new RuntimeException("some message");
...
ArgumentCaptor<Handler<AsyncResult<String>>> handlerCaptor =
ArgumentCaptor.forClass(Handler.class);
ArgumentCaptor<AsyncResult<String>> asyncResultCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
offerMongo.create(msg);
Mockito.verify(mongoClient,
Mockito.times(1)).insert(Mockito.anyString(), Mockito.any(), handlerCaptor.capture());
Mockito.verify(handlerCaptor.getValue(),
Mockito.times(1)).handle(asyncResultCaptor.capture());
Mockito.when(asyncResultCaptor.getValue().succeeded()).thenReturn(false);
Mockito.when(asyncResultCaptor.getValue().cause()).thenReturn(rex);
Assert.assertEquals(Json.encode(rex), msg.body().encode());
and using Answer:
ArgumentCaptor<AsyncResult<String>> handlerCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
AsyncResult<String> result = Mockito.mock(AsyncResult.class);
Mockito.when(result.succeeded()).thenReturn(true);
Mockito.when(result.cause()).thenReturn(rex);
Mockito.doAnswer(new Answer<MongoClient>() {
#Override
public MongoClient answer(InvocationOnMock invocation) throws Throwable {
((Handler<AsyncResult<String>>)
invocation.getArguments()[2]).handle(handlerCaptor.capture());
return null;
}
}).when(mongoClient).insert(Mockito.anyString(), Mockito.any(),
Mockito.any());
userMongo.create(msg);
Assert.assertEquals(Json.encode(rex), msg.body().encode());
And now I got confused. Is there a way to mock an AsyncResult to let it return false on succeed()?
Finally I got some times to investigate and I made it. Here is my solution.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(VertxUnitRunner.class)
#PrepareForTest({ MongoClient.class })
public class PersistenceTest {
private MongoClient mongo;
private Vertx vertx;
#Before
public void initSingleTest(TestContext ctx) throws Exception {
vertx = Vertx.vertx();
mongo = Mockito.mock(MongoClient.class);
PowerMockito.mockStatic(MongoClient.class);
PowerMockito.when(MongoClient.createShared(Mockito.any(), Mockito.any())).thenReturn(mongo);
vertx.deployVerticle(Persistence.class, new DeploymentOptions(), ctx.asyncAssertSuccess());
}
#SuppressWarnings("unchecked")
#Test
public void loadSomeDocs(TestContext ctx) {
Doc expected = new Doc();
expected.setName("report");
expected.setPreview("loremipsum");
Message<JsonObject> msg = Mockito.mock(Message.class);
Mockito.when(msg.body()).thenReturn(JsonObject.mapFrom(expected));
JsonObject result = new JsonObject().put("name", "report").put("preview", "loremipsum");
AsyncResult<JsonObject> asyncResult = Mockito.mock(AsyncResult.class);
Mockito.when(asyncResult.succeeded()).thenReturn(true);
Mockito.when(asyncResult.result()).thenReturn(result);
Mockito.doAnswer(new Answer<AsyncResult<JsonObject>>() {
#Override
public AsyncResult<JsonObject> answer(InvocationOnMock arg0) throws Throwable {
((Handler<AsyncResult<JsonObject>>) arg0.getArgument(3)).handle(asyncResult);
return null;
}
}).when(mongo).findOne(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
Async async = ctx.async();
vertx.eventBus().send("persistence", new JsonObject(), msgh -> {
if (msgh.failed()) {
System.out.println(msgh.cause().getMessage());
}
ctx.assertTrue(msgh.succeeded());
ctx.assertEquals(expected, Json.decodeValue(msgh.result().body().toString(), Doc.class));
async.complete();
});
async.await();
}
}
Use Powemockito to mock the MongoClient.createShared static method, so you'll have your mock when verticle starts. Mocking async handler is a bit of code to write. As you can see mocking start at Message<JsonObject> msg = Mockito.mock(Message.class); and ends at Mockito.doAnswer(new Answer.... In the Answer's method pick the handler param and force it to handle your async result then you're done.
Normally, I'd use a comment to post this, but formatting gets lost. The accepted solution is works great, just note that it can be simplified a bit using Java 8+, and you can use your actual objects instead of JSON.
doAnswer((Answer<AsyncResult<List<Sample>>>) arguments -> {
((Handler<AsyncResult<List<Sample>>>) arguments.getArgument(1)).handle(asyncResult);
return null;
}).when(sampleService).findSamplesBySampleFilter(any(), any());
getArgument(1), refers to the index of the handler argument in a method such as:
#Fluent
#Nonnull
SampleService findSamplesBySampleFilter(#Nonnull final SampleFilter sampleFilter,
#Nonnull final Handler<AsyncResult<List<Sample>>> resultHandler);