How to check if a parameter contains two substrings using Mockito? - java

I have a line in my test that currently looks like:
Mockito.verify(mockMyObject).myMethod(Mockito.contains("apple"));
I would like to modify it to check if the parameter contains both "apple" and "banana". How would I go about this?

Just use Mockito.matches(String), for example:
Mockito.verify(mockMyObject).
myMethod(
Mockito.matches("(.*apple.*banana.*)|(.*banana.*apple.*)"
)
);

Since Java 8 and Mockito 2.1.0, it is possible to use Streams as follows:
Mockito.verify(mockMyObject).myMethod(
Mockito.argThat(s -> s.contains("apple") && s.contains("banana"))
);
thus improving readability

I think the easiest solution is to call the verify() multiple times:
verify(emailService).sendHtmlMail(anyString(), eq(REPORT_TITLE), contains("Client response31"));
verify(emailService).sendHtmlMail(anyString(), eq(REPORT_TITLE), contains("Client response40"));
verify(emailService, never()).sendHtmlMail(anyString(), anyString(), contains("Client response30"));

Maybe this is not relevant anymore but I found another way to do it, following Torsten answer and this other answer. In my case I used Hamcrest Matchers
Mockito.verify(mockMyObject).myMethod(
Mockito.argThat(Matchers.allOf(
Matchers.containsString("apple"),
Matchers.containsString("banana"))));

You can also use Mockito's AdditionalMatchers:
Mockito.verify(mockMyObject).myMethod(
AdditionalMatchers.and(Mockito.contains("apple"), Mockito.contains("banana")));
More info https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/AdditionalMatchers.html#and(T,T)

Related

How to assert on the existence of a certain value in an array

class Configuration { String name, String type }
Configuration[] configurations = ..
I want to put a assert check to see if the array contains a certain value in the name field (say name="Any"). We are currently looping the array to check this, what would be an elegant way
Using the Streams API:
assertTrue(Arrays.stream(configurations).anyMatch(c -> "Any".equals(c.name));
Another slight variation using the Streams API and a method reference:
assertTrue(Arrays
.stream(configurations)
.map(c -> c.name)
.anyMatch("ValueToLookFor"::equals));
Use AssertJ:
assertThat(configurations).extracting(Configuration::getName).contains("Any");
or you may prefer:
assertThat(configurations).anyMatch(c -> "Any".equals(c.name));

Trouble using ArgumentMatchers in Mockito using when()

I'm writing some unit test with Mockito and I have the following situation:
AmazonS3 mockedS3 = Mockito.mock( AmazonS3.class )
Bucket mockBucket = Mockito.mock( Bucket.class )
Mockito.when( mockBucket.getName() ).thenReturn("bucket-1-pub")
Mockito.when(mockedS3.doesBucketExistV2("bucket-1-pub")).thenReturn(false)
// here I'm setting up a mock that accepts any CreateBucketRequest
Mockito.when( mockedS3.createBucket(any(CreateBucketRequest.class)) )
.thenReturn( mockBucket )
// execute the code under test
String result = doSomething()
// this is the line of the error where it doesn't see a call to createBucket
// for any CreateBucketRequest
Mockito.verify( mockedS3 ).createBucket( any(CreateBucketRequest.class) )
Here is the error I get:
Wanted but not invoked:
amazonS3.createBucket(
<any com.amazonaws.services.s3.model.CreateBucketRequest>
);
-> at com.amazonaws.services.s3.AmazonS3$createBucket$3.call(Unknown Source)
However, there were exactly 2 interactions with this mock:
amazonS3.doesBucketExistV2("bucket-1-pub");
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:142)
amazonS3.createBucket(
com.amazonaws.services.s3.model.CreateBucketRequest#255e5e2e
);
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:147)
Wanted but not invoked:
amazonS3.createBucket(
<any com.amazonaws.services.s3.model.CreateBucketRequest>
);
-> at com.amazonaws.services.s3.AmazonS3$createBucket$3.call(Unknown Source)
However, there were exactly 2 interactions with this mock:
amazonS3.doesBucketExistV2("bucket-1-pub");
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:142)
amazonS3.createBucket(
com.amazonaws.services.s3.model.CreateBucketRequest#255e5e2e
);
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:147)
So from tracing out the call my amazonS3.createBucket() call is being called with a CreateBucketRequest, but instead of returning the mockBucket that I have configured. It just returns null, then when I verify it was called that call doesn't match the conditions of verify and blamo exception city.
Update: Things I've tried have been to move the when() calls so they align with the order in which the methods will be called in the code. Didn't work. (I glad that didn't work because how awful would that be?! So much for black box testing right?) I also tried to remove the verify() call for createBucket(). That just resulted in the next verify (not pictured) to blow up because createBucket() still didn't return what I configured.
I can't see how this isn't working so I need some help to see my mistake.
Ok so I left out an important detail my apologies to those who commented. I'm writing my test with Groovy. And it turns out it's Groovy's fault. I started to suspect that Groovy was adding it's Groovy methods to Objects and that might make them appear not the same to Mockito. So while it says it had an interaction with createBucket(CreateBucketRequest). It wasn't recognizing CreateBucketRequest and CreateBucketRequest + Groovy Default Methods as the same thing when using any() matcher.
Now why this is happening is for the Mockito devs to figure out. I suppose I should just go use Spock instead of junit, but that is for another day. Thanks for the help.

ClassGraph, how to filter the classpath's content

I try to find an answer to the following question. If somebody has a hint, i would appreciate.
I try to find the runtime classpath using ClassGraph:
String classpath = new ClassGraph().getClasspath();
The classpath content looks as follows:
C:\work\WildFlyAppServer\WildFlyAppServer14\jre\windows64\lib\ext\access-bridge-64.jar;
C:\work\WildFlyAppServer\WildFlyAppServer14\jre\windows64\lib\ext\cldrdata.jar;
C:\work\WildFlyAppServer\WildFlyAppServer14\jre\windows64\lib\ext\dnsns.jar;
C:\work\WildFlyAppServer\WildFlyAppServer14\jre\windows64\lib\ext\jaccess.jar;
C:\work\WildFlyAppServer\WildFlyAppServer14\jre\windows64\lib\ext\localedata.jar;
C:\work\WildFlyAppServer\WildFlyAppServer14\jre\windows64\lib\ext\nashorn.jar;
...
C:\work\dev\MyWebApplication\myapp\exploded-jb7\myapp.ear\myapp.war\WEB-INF\lib\myjar1.jar;
C:\work\dev\MyWebApplication\myapp\exploded-jb7\myapp.ear\myapp.war\WEB-INF\lib\myjar2.jar;
C:\work\dev\MyWebApplication\myapp\exploded-jb7\myapp.ear\myapp.war\WEB-INF\lib\myjar3.jar;
C:\work\dev\MyWebApplication\myapp\exploded-jb7\myapp.ear\myapp.war\WEB-INF\lib\myjar4.jar;
...
C:\work\WildFlyAppServer\WildFlyAppServer14\server\myapp\tmp\vfs\deployment\deployment82593206c83a71cc\myjar1.jar-a43b90541d67f63b\myjar1.jar;
C:\work\WildFlyAppServer\WildFlyAppServer14\server\myapp\tmp\vfs\deployment\deployment82593206c83a71cc\myjar2.jar-fc9118a07f840a67\myjar2.jar;
.....
C:\work\WildFlyAppServer\WildFlyAppServer14\modules\system\layers\base\com\sun\xml\bind\main\jaxb-core-2.3.0.jar;
C:\work\WildFlyAppServer\WildFlyAppServer14\modules\system\layers\base\com\sun\xml\bind\main\jaxb-runtime-2.3.0.jar;
....
I would like to filter, for example, the jars that comes from: C:\work\WildFlyAppServer\WildFlyAppServer14\server\myapp\tmp
Does anybody know how to do this?
Thanks a lot!
Even though I haven't used ClassGraph, with a quick look at the documentation I think you should use this method to create your ClassGraph object and pass an implementation of this functional interface as a parameter.
So basically something along the lines of:
ClasspathElementFilter classpathElementFilter = (java.lang.String classpathElementPathStr) -> {
/* here check whether classpathElementPathStr is a path you want to scan.
If yes return true */
}
ClassGraph myClassGraph = filterClasspathElements(classpathElementFilter);
String classpath = myClassGraph.getClasspath();
I hope this was helpful.

How to fix this problem with assertEquals in Junit?

Please help me with the following problem, My Junit test fails because my output is
"09:39:43.704 [main] INFO by.iba.gomel.ShapeController - 145"
But i need just "145" ShapeController.LOGGER.info("{}", ShapeController.sum);
#Test
public void testSumma() {
final Shape[] newShapes = new Shape[5];
ShapeController.initializeArray(newShapes);
ShapeController.summa(newShapes);
Assert.assertEquals("these objects should be equal", "145", this.log.getLog());
}
If you are not changing the log format and the class name you can use this.log.getLog().split("ShapeController - ")[1].
But be wary of such hard-coded things. Anyways if you change something this test case will break and notify you.
You can use Java Library such as Hamcrest to make an assertion in a sentence if it ends with the number or word, such as 1 :
assertThat("myStringOfNote", endsWith("Note"))
This can be translated into your use case as :
assertThat(this.log.getLog(), endsWith("145"))

Configure mockito to print actual argument values in verification error messages

When describing failed verification, by default Mockito prints only call sites where interactions happened. Like this:
Wanted but not invoked:
proxyListener.foundTemplateParam(
"fooBar2",
isNull(),
isNull()
);
-> at foo.ProxyHandlerTest.testThatImplicitParamsScannedCorrectly(ProxyHandlerTest.java:136)
However, there were other interactions with this mock:
-> at foo.ProxyHandler.<init>(ProxyHandler.java:99)
-> at foo.ProxyHandler.<init> (ProxyHandler.java:100)
-> at foo.ProxyHandler.scanForParamSetters(ProxyHandler.java:222)
-> at foo.ProxyHandler.<init>(ProxyHandler.java:102)
-> at foo.ProxyHandler.<init>(ProxyHandler.java:104)
That's useful information but I would also like to see what arguments where passed during those interactions. Is there a way to achieve this?
P. S. I know about mocking with withSettings().verboseLogging(). But it's too verbose and is printed to stdout instead of adding this info to assertion error message.
Update:
Mockito 1.9.0 doesn't support customization of exception error messages out of the box (I just checked their sources).
the safest place to do that is an answer that prints arguments and return the given value.
You could then write something like :
given(some.callWith(arg1, arg2)).will(printArgsAndReturn("some value"));
where printArgsAndReturn("some value") actually returns your custom answer.

Categories