I'm running into a generics problem with Mockito and Hamcrest.
Please assume the following interface:
public interface Service {
void perform(Collection<String> elements);
}
And the following test snippet:
Service service = mock(Service.class);
// ... perform business logic
verify(service).perform(Matchers.argThat(contains("a", "b")));
So I want to verify that my business logic actually called the service with a collection that contains "a" and "b" in that order.
However, the return type of contains(...) is Matcher<Iterable<? extends E>>, so Matchers.argThat(...) returns Iterable<String> in my case, which naturally does not apply to the required Collection<String>.
I know that I could use an argument captor as proposed in Hamcrest hasItem and Mockito verify inconsistency, but I would very much like not to.
Any suggestions!
Thanks!
You can just write
verify(service).perform((Collection<String>) Matchers.argThat(contains("a", "b")));
From the compiler's point of view, this is casting an Iterable<String> to a Collection<String> which is fine, because the latter is a subtype of the former. At run time, argThat will return null, so that can be passed to perform without a ClassCastException. The important point about it is that the matcher gets onto Mockito's internal structure of arguments for verification, which is what argThat does.
As an alternative one could change the approach to ArgumentCaptor:
#SuppressWarnings("unchecked") // needed because of `List<String>.class` is not a thing
// suppression can be worked around by using #Captor on a field
ArgumentCaptor<List<String>> captor = ArgumentCaptor.forClass(List.class);
verify(service).perform(captor.capture());
assertThat(captor.getValue(), contains("a", "b"));
Notice, that as a side effect this decouples the verification from the Hamcrest library, and allows you to use any other library (e.g. Truth):
assertThat(captor.getValue()).containsExactly("a", "b");
If you get stuck in situations like these, remember that you can write a very small reusable adapter.
verify(service).perform(argThat(isACollectionThat(contains("foo", "bar"))));
private static <T> Matcher<Collection<T>> isACollectionThat(
final Matcher<Iterable<? extends T>> matcher) {
return new BaseMatcher<Collection<T>>() {
#Override public boolean matches(Object item) {
return matcher.matches(item);
}
#Override public void describeTo(Description description) {
matcher.describeTo(description);
}
};
}
Note that David's solution above, with casting, is the shortest right answer.
You can put your own lambda as an ArgumentMatcher
when(myClass.myMethod(argThat(arg -> arg.containsAll(asList(1,2))))
.thenReturn(...);
Why not just verify with the expected arguments, assuming the list only contains the two items, e.g.:
final List<String> expected = Lists.newArrayList("a", "b");
verify(service).perform(expected);
Whilst I agree with Eugen in principle, I think that relying on equals for String comparison is acceptable... besides, the contains matcher uses equals for comparison anyway.
Similar to another answer here you can do the following:
verify(yourmock, times(1)).yourmethod(argThat(arg -> arg.containsAll(asList("a", "b"))));
You could have your own java.util.Collection implementation and override the equals method like below.
public interface Service {
void perform(Collection<String> elements);
}
#Test
public void testName() throws Exception {
Service service = mock(Service.class);
service.perform(new HashSet<String>(Arrays.asList("a","b")));
Mockito.verify(service).perform(Matchers.eq(new CollectionVerifier<String>(Arrays.asList("a","b"))));
}
public class CollectionVerifier<E> extends ArrayList<E> {
public CollectionVerifier() {
}
public CollectionVerifier(final Collection<? extends E> c) {
super(c);
}
#Override
public boolean equals(final Object o) {
if (o instanceof Collection<?>) {
Collection<?> other = (Collection<?>) o;
return this.size() == other.size() && this.containsAll(other);
}
return false;
}
}
Related
I am defining a type Option<T> in Java that should behave as much as possible as Rust's equivalent.
It has a method, Option::flatten, that is only implemented if the inner T is some other Option<T>. I am thinking of something like this:
public class Option<T> {
/* fields, constructors, other methods */
#Bound(T=Option<U>)
public <U> Option<U> flatten() {
if (isNone()) return None();
else return this.unwrap();
}
}
But the syntax is of course completely fictional. Is there some way to make this work in Java? I know static methods are an option, but they can't be called like a normal method which is the only goal of this type.
This is not supposed to be a standalone thing, but rather a part of a larger Java implementation of Rust iterators I'm currently working on.
The problem with trying to come up with a non-static method such as flatten is that in Java one cannot conditionally add more methods to a class based on whether the type parameter of the class fulfills a certain constraint.
You can, however, make it a static method and constrain its arguments to whatever you need.
class Option<T> {
// ...
public static <U> Option<U> flatten(Option<Option<U>> option) {
if (option.isNone()) return None();
return option.unwrap();
}
}
Which would work for valid implementations of None, isNone and unwrap.
A more complete example follows.
public static class Option<T> {
private final T value;
private Option(T x) {
this.value = x;
}
public static <T> Option<T> of(T x) {
java.util.Objects.requireNonNull(x);
return new Option<>(x);
}
public static <T> Option<T> None() {
return new Option<>(null);
}
public T unwrap() {
java.util.Objects.requireNonNull(this.value);
return this.value;
}
public boolean isNone() {
return this.value == null;
}
public static <U> Option<U> flatten(Option<Option<U>> option) {
if (option.isNone()) return Option.None();
return option.unwrap();
}
#Override
public String toString() {
if (this.isNone()) {
return "None";
}
return "Some(" + this.value.toString() + ")";
}
}
Usage:
var myOption = Option.of(Option.of(5));
System.out.println("Option: " + myOption);
System.out.println("Flattened: " + Option.flatten(myOption));
Output:
Option: Some(Some(5))
Flattened: Some(5)
I think the way you want to handle this is not to actually have a flatten() method, but have different handling in your constructor. Upon being created, the constructor should check the type it was handed. If that type is Option, it should try and unwrap that option, and set its internal value to the same as the option it was handed.
Otherwise, there isn't really a way for an object to 'flatten' itself, because it would have to change the type it was bounded over in the base case. You could return a new object from a static method, but are otherwise stuck.
I want to point out some of the potential headaches and issues regarding this re-implementation of Optional<T>.
Here's how I would initially go about it:
public class Option<T> {
/* fields, constructors, other methods */
public <U> Option<U> flatten() {
if (isNone()) return None();
T unwrapped = this.unwrap();
if (unwrapped instanceof Option) {
return (Option<U>) unwrapped; //No type safety!
} else {
return (Option<U>) this;
}
}
}
However, this code is EVIL. Note the signature of <U> Option<U> flatten() means that the U is going to be type-inferenced into whatever it needs to be, not whatever a potential nested type is. So now, this is allowed:
Option<Option<Integer>> opt = /* some opt */;
Option<String> bad = opt.flatten();
Option<Option<?>> worse = opt.<Option<?>>flatten();
You will face a CCE upon using this for the other operations, but it allows a type of failure which I would say is dangerous at best. Note that any Optional<Optional<T>> can have #flatMap unwrap for you: someOpt.flatMap(Function.identity());, however this again begs the question of what caused you to arrive at a wrapped optional to begin with.
Another answer (by #NathanielFord) notes the constructor as an option, which seems viable as well, but will still face the runtime check upon construction (with it simply being moved to the constructor):
public class Option<T> {
/* fields, constructors, other methods */
public Option<T>(T someValue) { ... }
public Option<T>(Option<T> wrapped) {
this(wrapped.isNone() ? EMPTY_OBJECT : wrapped.unwrap());
}
public Option<T> flatten() {
return this; //we're always flattened!
}
}
Note as well, the re-creation of Optional<T> by
#E_net4thecommentflagger has the potential for a nasty future bug: Optional.ofNullable(null).isNone() would return true! This may not be what you want for some potential use-cases, and should #equals be implemented in a similar manner, you'd end up with Optional.ofNullable(null).equals(Optional.None()), which seems very counter-intuitive.
All of this to say, that while Rust may require you to deal with these nested optionals, you are writing code for Java, and many of the potential restrictions you faced before have changed.
Question
Assume the following simple test:
#Test
public void test() throws Exception {
Object value = 1;
assertThat(value, greaterThan(0));
}
The test won't compile, because "greaterThan" can only be applied to instances of type Comparable. But I want to assert that value is an Integer which is greater than zero. How can I express that using Hamcrest?
What I tried so far:
The simple solution would be to simply remove the generics by casting the matcher like that:
assertThat(value, (Matcher)greaterThan(0));
Possible, but generates a compiler warning and feels wrong.
A lengthy alternative is:
#Test
public void testName() throws Exception {
Object value = 1;
assertThat(value, instanceOfAnd(Integer.class, greaterThan(0)));
}
private static<T> Matcher<Object> instanceOfAnd(final Class<T> clazz, final Matcher<? extends T> submatcher) {
return new BaseMatcher<Object>() {
#Override
public boolean matches(final Object item) {
return clazz.isInstance(item) && submatcher.matches(clazz.cast(item));
}
#Override
public void describeTo(final Description description) {
description
.appendText("is instanceof ")
.appendValue(clazz)
.appendText(" and ")
.appendDescriptionOf(submatcher);
}
#Override
public void describeMismatch(final Object item, final Description description) {
if (clazz.isInstance(item)) {
submatcher.describeMismatch(item, description);
} else {
description
.appendText("instanceof ")
.appendValue(item == null ? null : item.getClass());
}
}
};
}
Feels "tidy" and "correct", but it is really a lot of code for something that seems simple. I attempted to find something like that built-in in hamcrest, but I was not successful, but maybe I missed something?
Background
In my actual test case the code is like this:
Map<String, Object> map = executeMethodUnderTest();
assertThat(map, hasEntry(equalTo("the number"), greaterThan(0)));
In my simplified case in the question I could also write assertThat((Integer)value, greaterThan(0)). In my actual case I could write assertThat((Integer)map.get("the number"), greaterThan(0)));, but that would of course worsen the error message if something is wrong.
This answer will not show how to do this using Hamcrest, I do not know if there is a better way than the proposed.
However, if you have the possibility to include another test library, AssertJ supports exactly this:
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class TestClass {
#Test
public void test() throws Exception {
Object value = 1;
assertThat(value).isInstanceOfSatisfying(Integer.class, integer -> assertThat(integer).isGreaterThan(0));
}
}
No need for any casting, AssertJ does this for you.
Also, it prints a pretty error message if the assertion fails, with value being too small:
java.lang.AssertionError:
Expecting:
<0>
to be greater than:
<0>
Or if value is not of the correct type:
java.lang.AssertionError:
Expecting:
<"not an integer">
to be an instance of:
<java.lang.Integer>
but was instance of:
<java.lang.String>
The Javadoc for isInstanceOfSatisfying(Class<T> type, Consumer<T> requirements) can be found here, which also contains some examples of sligthly more complicated assertions:
// second constructor parameter is the light saber color
Object yoda = new Jedi("Yoda", "Green");
Object luke = new Jedi("Luke Skywalker", "Green");
Consumer<Jedi> jediRequirements = jedi -> {
assertThat(jedi.getLightSaberColor()).isEqualTo("Green");
assertThat(jedi.getName()).doesNotContain("Dark");
};
// assertions succeed:
assertThat(yoda).isInstanceOfSatisfying(Jedi.class, jediRequirements);
assertThat(luke).isInstanceOfSatisfying(Jedi.class, jediRequirements);
// assertions fail:
Jedi vader = new Jedi("Vader", "Red");
assertThat(vader).isInstanceOfSatisfying(Jedi.class, jediRequirements);
// not a Jedi !
assertThat("foo").isInstanceOfSatisfying(Jedi.class, jediRequirements);
The problem is that you lose the type information here:
Object value = 1;
This is an insanely weird line, if you think about it. Here value is the most generic thing possible, nothing can be reasonably told about it, except maybe checking if it's null or checking its string representation if it's not. I'm sort of at loss trying to imagine a legitimate use case for the above line in modern Java.
The obvious fix would be assertThat((Comparable)value, greaterThan(0));
A better fix would be casting to Integer, because you're comparing to an integer constant; strings are also comparable but only between themselves.
If you can't assume that your value is even Comparable, comparing it to anything is pointless. If your test fails on the cast to Comparable, it's a meaningful report that you dynamic casting to Object from something else failed.
How about a slighly modified version of your original attempt:
#Test
public void testName() throws Exception {
Map<String, Object> map = executeMethodUnderTest();
assertThat(map, hasEntry(equalTo("the number"),
allOf(instanceOf(Integer.class), integerValue(greaterThan(0)))));
}
private static<T> Matcher<Object> integerValue(final Matcher<T> subMatcher) {
return new BaseMatcher<Object>() {
#Override
public boolean matches(Object item) {
return subMatcher.matches(Integer.class.cast(item));
}
#Override
public void describeTo(Description description) {
description.appendDescriptionOf(subMatcher);
}
#Override
public void describeMismatch(Object item, Description description) {
subMatcher.describeMismatch(item, description);
}
};
}
Now the custom matcher is a little less verbose and you still achieve what you want.
If the value is too small:
java.lang.AssertionError:
Expected: map containing ["the number"->(an instance of java.lang.Integer and a value greater than <0>)]
but: map was [<the number=0>]
If the value is wrong type:
java.lang.AssertionError:
Expected: map containing ["the number"->(an instance of java.lang.Integer and a value greater than <0>)]
but: map was [<the number=something>]
The problem with map containing Object values is that you have to assume the specific class to compare.
What hamcrest is lacking is a way to transform a matcher from a given type to another, such as the one in this gist:
https://gist.github.com/dmcg/8ddf275688fd450e977e
public class TransformingMatcher<U, T> extends TypeSafeMatcher<U> {
private final Matcher<T> base;
private final Function<? super U, ? extends T> function;
public TransformingMatcher(Matcher<T> base, Function<? super U, ? extends T> function) {
this.base = base;
this.function = function;
}
#Override
public void describeTo(Description description) {
description.appendText("transformed version of ");
base.describeTo(description);
}
#Override
protected boolean matchesSafely(U item) {
return base.matches(function.apply(item));
}
}
With that, you could write your asserts this way:
#Test
public void testSomething() {
Map<String, Object> map = new HashMap<>();
map.put("greater", 5);
assertThat(map, hasEntry(equalTo("greater"), allOf(instanceOf(Number.class),
new TransformingMatcher<>(greaterThan((Comparable)0), new Function<Object, Comparable>(){
#Override
public Comparable apply(Object input) {
return Integer.valueOf(input.toString());
}
}))));
}
But the problem, again, is that you need to specify a given Comparable numeric class (Integer in this case).
In case of assertion error the message would be:
java.lang.AssertionError
Expected: map containing ["string"->(an instance of java.lang.Number and transformed version of a value greater than <0>)]
but: map was [<string=NaN>]
If my method call is:
obj.getLevelOne().getLevelTwo().getValue();
And I want to pass this method as a parameter below:
boolean checkValue( obj, method , value)
{
return obj.method() == value;
}
I want to call the checkValue method like this:
checkValue(obj, "getLevelOne().getLevelTwo().getValue", value);
Is there any way I can accomplish this? Please help.
In java Functions are not a first class concept (yet, coming in Java 8). So it's not possible to pass a method as you can in many other languages that have functional concepts.
What you need to do instead is declare an interface and implement it using an anonymous inner class. e.g.
The Interface
interface MyGetter {
Object doGet();
}
The Check Method
boolean checkValue(MyGetter getter, Object value) {
return getter.doGet().equals(value);
}
The Call
checkValue(new MyGetter() {
public Object doGet() {
return obj.getLevelOne().getLevelTwo().getValue();
}
}, 5);
What we're actually doing in the call is creating a new class and an object of that type to make the actual call you need.
Edit:
If you need different return types you can make the interface and check method generic, e.g.
The Interface
interface MyGetter<T> {
T doGet();
}
The Check Method
<T> boolean checkValue(MyGetter<? extends T> getter, T value) {
return getter.doGet().equals(value);
}
The Call
checkValue(new MyGetter<SomeClass>() {
public SomeClass doGet() {
return obj.getLevelOne().getLevelTwo().getValue();
}
}, 5);
If you really want to do something like this, i recommend either:
1.use a Callable and create anonymous subclasses. NOTE: this is somewhat similar to the approach given above with "MyGetter", except that it uses Callable. There's no need for our own interface, since we can use something that was intended for this purpose that's built into the jdk.
public <T> boolean checkValue(Callable<T> valueGetter, T value) {
return value.equals(valueGetter.call());
}
final MyObject obj = new MyObject();
checkValue(new Callable<String>() {
public String call() { return obj.getLevelOne().getLevelTwo().getValue(); }
}, "foo");
2.using some sort of EL package (mvel works well as an embedded library).
You could then do: "levelOne.levelTwo.value" as your expression, and use mvel to evaluated in on "obj".
public <T> boolean checkValue(Object obj, String expression, T value) {
Object objVal = MVEL.eval(expression, obj);
return value.equals(objVal);
}
checkValue(obj, "levelOne.levelTwo.value", "foo");
Of course, the first one is much more typesafe, though your "expression" would be done at compile time since you're explicitly coding it into the callable implemention. The second approach is more dynamic and lets you compute the expression at runtime.
When you use the Visitor pattern and you need to get a variable inside visitor method, how to you proceed ?
I see two approaches. The first one uses anonymous class :
// need a wrapper to get the result (which is just a String)
final StringBuild result = new StringBuilder();
final String concat = "Hello ";
myObject.accept(new MyVisitor() {
#Override
public void visit(ClassA o)
{
// this concatenation is expected here because I've simplified the example
// normally, the concat var is a complex object (like hashtable)
// used to create the result variable
// (I know that concatenation using StringBuilder is ugly, but this is an example !)
result.append(concat + "A");
}
#Override
public void visit(ClassB o)
{
result.append(concat + "B");
}
});
System.out.println(result.toString());
Pros & Cons :
Pros : you do not need to create a class file for this little behavior
Cons : I don't like the "final" keyword in this case : the anonymous class is less readable because it calls external variables and you need to use a wrapper to get the requested value (because with the keyword final, you can't reassign the variable)
Another way to do it is to do an external visitor class :
public class MyVisitor
{
private String result;
private String concat;
public MyVisitor(String concat)
{
this.concat = concat;
}
#Override
public void visit(ClassA o)
{
result = concat + "A";
}
#Override
public void visit(ClassB o)
{
result = concat + "B";
}
public String getResult()
{
return result;
}
}
MyVisitor visitor = new MyVisitor("Hello ");
myObject.accept(visitor);
System.out.println(visitor.getResult());
Pros & Cons :
Pros : all variables are defined in a clean scope, you don't need a wrapper to encapsulate the requested variable
Cons : need an external file, the getResult() method must be call after the accept method, this is quite ugly because you need to know the function call order to correctly use the visitor
You, what's your approach in this case ? Preferred method ? another idea ?
Well, both approaches are valid and imo, it really depends on whether you would like to reuse the code or not. By the way, your last 'Con' point is not totally valid since you do not need an 'external file' to declare a class. It might very well be an inner class...
That said, the way I use Visitors is like this:
public interface IVisitor<T extends Object> {
public T visit(ClassA element) throws VisitorException;
public T visit(ClassB element) throws VisitorException;
}
public interface IVisitable {
public <T extends Object> T accept(final IVisitor<T> visitor) throws VisitorException;
}
public class MyVisitor implements IVisitor<String> {
private String concat;
public MyVisitor(String concat) {
this.concat = concat;
}
public String visit(ClassA classA) throws VisitorException {
return this.concat + "A";
}
public String visit(ClassB classB) throws VisitorException {
return this.concat + "B";
}
}
public class ClassA implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
public class ClassB implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
// no return value needed?
public class MyOtherVisitor implements IVisitor<Void> {
public Void visit(ClassA classA) throws VisitorException {
return null;
}
public Void visit(ClassB classB) throws VisitorException {
return null;
}
}
That way, the visited objects are ignorant of what the visitor wants to do with them, yet they do return whatever the visitor wants to return. Your visitor can even 'fail' by throwing an exception.
I wrote the first version of this a few years ago and so far, it has worked for me in every case.
Disclaimer: I just hacked this together, quality (or even compilation) not guaranteed. But you get the idea... :)
I do not see an interface being implemented in your second example, but I believe it is there. I would add to your interface (or make a sub interface) that has a getResult() method on it.
That would help both example 1 and 2. You would not need a wrapper in 1, because you can define the getResult() method to return the result you want. In example 2, because getResult() is a part of your interface, there is no function that you 'need to know'.
My preference would be to create a new class, unless each variation of the class is only going to be used once. In which case I would inline it anonymously.
From the perspective of a cleaner design, the second approach is preferrable for the same exact reasons you've already stated.
In a normal TDD cycle I would start off with an anonymous class and refactored it out a bit later. However, if the visitor would only be needed in that one place and its complexity would match that of what you've provided in the example (i.e. not complex), I would have left it hanging and refactor to a separate class later if needed (e.g. another use case appeared, complexity of the visitor/surrounding class increased).
I would recommend using the second approach. Having the visitor in its full fledged class also serves the purpose of documentation and clean code. I do not agree with the cons that you have mentioned with the approach. Say you have an arraylist, and you don't add any element to it and do a get, surely you will get a null but that doesn't mean that it is necessarily wrong.
One of the points of the visitor pattern is to allow for multiple visitor types. If you create an anonymous class, you are kind of breaking the pattern.
You should change your accept method to be
public void accept(Visitor visitor) {
visitor.visit(this);
}
Since you pass this into the visitor, this being the object that is visited, the visitor can access the object's property according to the standard access rules.
Why is the compiler unable to infer the correct type for the result from Collections.emptySet() in the following example?
import java.util.*;
import java.io.*;
public class Test {
public interface Option<A> {
public <B> B option(B b, F<A,B> f);
}
public interface F<A,B> {
public B f(A a);
}
public Collection<String> getColl() {
Option<Integer> iopt = null;
return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
public Collection<String> f(Integer i) {
return Collections.singleton(i.toString());
}
});
}
}
Here's the compiler error message:
knuttycombe#knuttycombe-ubuntu:~/tmp/java$ javac Test.java
Test.java:16: <B>option(B,Test.F<java.lang.Integer,B>) in
Test.Option<java.lang.Integer> cannot be applied to (java.util.Set<java.lang.Object>,
<anonymous Test.F<java.lang.Integer,java.util.Collection<java.lang.String>>>)
return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
^
1 error
Now, the following implementation of getColl() works, of course:
public Collection<String> getColl() {
Option<Integer> iopt = null;
Collection<String> empty = Collections.emptySet();
return iopt.option(empty, new F<Integer, Collection<String>>() {
public Collection<String> f(Integer i) {
return Collections.singleton(i.toString());
}
});
}
and the whole intent of the typesafe methods on Collections is to avoid this sort of issue with the singleton collections (as opposed to using the static variables.) So is the compiler simply unable to perform inference across multiple levels of generics? What's going on?
Java needs a lot of hand holding with its inference. The type system could infer better in a lot of cases but in your case the following will work:
print("Collections.<String>emptySet();");
First you can narrow down your problem to this code:
public class Test {
public void option(Collection<String> b) {
}
public void getColl() {
option(Collections.emptySet());
}
}
This does not work, you need a temporary variable or else the compiler cannot infer the type. Here is a good explanation of this problem: Why do temporary variables matter in case of invocation of generic methods?
Collections.emptySet() is not a Collection<String> unless Java knows that it needs a Collection<String> there. In this case, it appears that the compiler is being somewhat silly about the order that it tries to determine types, and tries to determine the return type of Collections.emptySet() before trying to determine the intended template parameter type for B is actually String.
The solution is to explictly state that you need Collections.<String>emptySet(), as mentioned by GaryF.
It looks like a typecasting issue - i.e., that it's being required to cast Object (in Set<Object>, which would be the type of the empty set) to String. Downcasts are not, in the general case, safe.