JUnit assertThat: check that Object equals String - java

I have Map declared as following:
Map<String, Object> data
I put a String in it and verify its value like this:
assertEquals("value", data.get("key"));
Now, I'd like to rewrite the verification to use assertThat instead of assertEquals. I've tried the following:
assertThat(data.get("key"), equalTo("value"));
And of course it didn't work because of type mismatch:
Wrong 2nd argument type. Found: 'org.hamcrest.Matcher<java.lang.String>', required: 'org.hamcrest.Matcher<? super java.lang.Object>' less...
Explicit type cast of the first argument to String helps, but I'd like to avoid it. For example assertEquals doesn't require type cast.
So, how can I check that the value, which was put into Map object, declared above, is equal to particular String, using the assertThat method?

The "more assertThat" way of doing things would be:
Map<String, Object> expectedData = Collections.singletonMap("key", "value");
asssertThat(data, is(expectedData));
Please note:
Maybe you need type hints for the call to singletonMap
Besides the is matcher, there are other matchers that would allow you to check that data contains your "expected" map data
For your specific problem: that is caused because how generics come into play here; it might be sufficient to use (String) data.get("key") - to tell the compiler that the "actual" argument is of type String.
In the end - I have no idea what your problem is. I wrote down this piece of code:
public void test() {
Map<String, Object> data = new HashMap<>();
data.put("key", "value");
assertThat(data.get("key"), is("value"));
Map<String, Object> expectedData = Collections.singletonMap("key", "value");
assertThat(data, is(expectedData));
}
It compiles fine, and the unit test runs and passes. In other words: actually I am unable to repro your problem.

try this
assertThat(data.get("key"), equalTo("value"))
or
assertThat(data.get("key"), CoreMatchers.equalTo("value"))

Related

Mockito: how to mock doAnswer for a generic method

I have a class that, in essence, looks like this:
class Checkpointer {
public <Input,Output> Output runFunction(Input input, Function<Input,Output> function) {
Output output;
// Sometimes run the function, sometimes return an Output from a cache
return output
}
}
I would like to mock this class using Mockito doAnswer:
Checkpointer checkpointer; // mocked via #Mock annotation
Mockito
.doAnswer(/* ??? */)
.when(checkpointer)
.runFunction(Mockito.any(), Mockito.any());
The function I want to mock needs to be generic. Can this be done?
For example, my first attempt produced the following. Not only did I resort to Object as the type arguments for Function, but the compiler was still unhappy with unchecked casting:
Mockito.doAnswer((invocation) ->
{
// compiler is not happy with this cast V
Function<Object,Object> function = (Function<Object,Object>)invocation.getArguments()[1];
return function.apply(invocation.getArgument(0));
}).when(checkpointer).runFunction(Mockito.any(), Mockito.any());
If this can't be done, I think can try writing my own mock class extending the first and use Mockito.spy.
The problem here is that you insist on using getArguments, which returns an Object[]
Since you know the index of the Function argument, you can use getArgument(index), as you're doing the line after that.
final Function<String, String> argument = invocation.getArgument(1);
Is this what you're looking for? Type inference for the getArgument generic type is working fine.
If not, can you provide a more elaborate example?

java reflections list NoSuchMethodException

I'm currently working on a commandline-client for automated testing. For this, I want to be able to perform a request just by a given name, so I have to use reflection.
However, I get the following error:
NoSuchMethodException: java.util.ArrayList.add(some.path.Foo)
on this code:
Object job = Class.forName(sClassName).getConstructor().newInstance();
List<?> jobObject = (List<?>) Request.getClass().getDeclaredMethod(sMethodName).invoke(Request);
jobObject.getClass().getDeclaredMethod("add", job.getClass()).invoke(Request, job);
On the other hand, the following code works (but is not the solution as Foo should be dynamic, not hardcoded)
Object job = Class.forName(sClassName).getConstructor().newInstance();
List<Foo> jobObject = (List<Foo>) Request.getClass().getDeclaredMethod(sMethodName)).invoke(Request);
jobObject.add((Foo)job);
Sidenote:
sClassName = some.path.Foo
.getDeclaredMethod(sMethod).invoke(Request) returns an Object (which is a List< Foo>)
What I want to achieve is to get the code working with dynamic inputs (for example Bar instead of Foo)
Due to type erasure, the method add of a List expects at runtime an object of type Object (in other words its signature is boolean add(Object o)) moreover you need to invoke it on jobObject not on Request as it is not a List, so your code should rather be:
jobObject.getClass().getDeclaredMethod("add", Object.class).invoke(jobObject, job);
Unless I miss something for me you don't even need reflection in this case
List<Object> jobObject = (List<Object>)...
jobObject.add(job);

SpEL Cannot Be Cast to Map

Having read the documentation on "Inline Maps" for Spring Expression Language, I am passing an object to a SpelExpressionParser and .toString()ing the Object, so to speak; however, in doing so, I am receiving the following error:
org.springframework.expression.spel.standard.SpelExpression cannot be
cast to java.util.Map
The Object passed to as the argument to the .parseExpression function is the result of the annotation #PreAuthorize("hasPermission(#object, {name: 'roofus', animal: 'dog'}) "affixed" to a method.
Through the PermissionEvaluator interface implementation, it is passed in its Object form to a method:
private boolean doSomething (Object animal) { //....
Within this method is found an #Autowired SpelExpressionEvaluator. This is used in the following way:
Map animalMap = (Map) parser.parseExpression(animal.toString());
Through debugging, I know that the .toString() method results in: {name=roofus, animal=dog}
Resulting in the aforementioned error. Am I missing something? The goal is to be able to pass in a "JSON"-esque String (as specified by the linked documentation) for evaluation purposes.
Your problem that parser.parseExpression can't return Map independently of circumstances .
Looks like you misunderstood the architecture a bit. The SpelParser is for building Expression object from the the String. After that you can evaluate that expression using one of its getValue() method.
So, only after the evaluation you can get your Map object:
Expression expression = parser.parseExpression("{name: 'roofus', animal: 'dog'}");
Map map = expression.getValue(Map.class);
animal is already a Map (notice the formatting in the OP of the .toString() result) and not in the correct format expected by the parser. In this case, you don't even need the parser if the objective is to retrieve information from the Map:
((Map<String, String>)animal).get("animal")
So, in response to the solution proposed by Artem Bilan, this would actually work:
Map animalMap = (Map) parser.parseExpression("{name: 'roofus', animal: 'dog'}").getValue();
However, again, what is actually received (and the cause of the problem in the OP) is: parser.parseExpression("{name=roofus, animal=dog}")

Mockito anyMapOf nested generics

I am attempting to verify that a method with the following signature was called:
public void process(Map<String, Set<String>> data) {
...
}
The nested parameterized Set is causing me difficulties. I can get it to verify correctly with the any() matcher like so:
verify(dataProcessor).process(Matchers.<Map<String, Set<String>>> any());
As described in Mockito: Verifying with generic parameters although annoyingly it doesn't work if I do a direct static import of Matchers.any and call it as just:
verify(dataProcessor).process(<Map<String, Set<String>>> any())
But anyMapOf(clazz, clazz) seems the more appropriate matcher in this case. Since you can't do Set.class I'm not sure how you would do this. The following doesn't work because of the lack of generic:
verify(dataProcessor).process(anyMapOf(String.class, Set.class));
Is it possible to verify this situation with anyMapOf or should I stick with Matchers.<>any()?
There's no way to use anyMapOf to do this. It's designed to help with the simple case of mapping simple classes to simple classes in Java 7, and yours is more complex than that.
Java 8 parameter inference improved, so in Java 8, you can just use any().
verify(dataProcessor).process(Matchers.any());
Barring that, the best way to make this look is either like you wrote above:
verify(dataProcessor).process(Matchers.<Map<String, Set<String>>>any());
Or by extracting the matcher to a static function, which gives Java just enough information it needs to infer the type on its own:
#Test public void yourTest() {
// ...
verify(dataProcessor).process(anyStringSetMap());
}
private static Map<String, Set<String>> anyStringSetMap() {
return any();
}
(Caveat: Note that the return value of anyStringSetMap() is null; it's the side-effect of calling any that you're looking for. The extracted method is just to inform the Java compiler of the expected return type; beware that doing anything fancier will probably break in really-quite-interesting ways.)

Java program runs fine but doesn't compile

I have a java program which runs properly.
But when I try to clean and build it in Netbeans it is choking on this line:
protected HashMap<String, ArrayList<HashMap<String,String>>> config1
config1 = new <String,ArrayList<HashMap<String,String>>> HashMap(); // build breaks here.
the error is:
cannot find symbol
symbol : constructor
<java.lang.String,java.util.ArrayList<java.util.HashMap<java.lang.String,java.lang.String>>
>HashMap()
You are placing your type parameters in wrong place. It comes in between HashMap and the (): -
config1 = new HashMap<String,ArrayList<HashMap<String,String>>>();
Also, its a good idea to have more generalized types rather than specific types in the declaration, and even in generic type parameters. So you should use Map instead of HashMap in declaration, and List instead of ArrayList in your type parameter: -
And actually, you don't need to break your declaration and initialization in two lines. Just have them in one single line. It looks more cleaner. So, you can change your two lines to: -
protected Map<String, List<Map<String,String>>> config1 =
new HashMap<String, List<Map<String,String>>>();
You have to put the class name before the generics.
config1 = new HashMap<String,ArrayList<HashMap<String,String>>>();
Generics should follow the class name. It should not be used before the class name. Correct your second line as below:
protected HashMap<String, ArrayList<HashMap<String,String>>> config1;
config1 = new HashMap <String,ArrayList<HashMap<String,String>>>();

Categories