There is a generic method that takes a class as parameter and I have problems stubbing it with Mockito. The method looks like this:
public <U extends Enum<U> & Error, T extends ServiceResponse<U>> T validate(
Object target, Validator validator, Class<T> responseClass,
Class<U> errorEnum);
It's god awful, at least to me... I could imagine living without it, but the rest of the code base happily uses it...
I was going to, in my unit test, stub this method to return a new empty object. But how do I do this with mockito? I tried:
when(serviceValidatorStub.validate(
any(),
isA(UserCommentRequestValidator.class),
UserCommentResponse.class,
UserCommentError.class)
).thenReturn(new UserCommentResponse());
but since I am mixing and matching matchers and raw values, I get "org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!"
The problem is, you cannot mix argument matchers and real arguments in a mocked call. So, rather do this:
when(serviceValidatorStub.validate(
any(),
isA(UserCommentRequestValidator.class),
eq(UserCommentResponse.class),
eq(UserCommentError.class))
).thenReturn(new UserCommentResponse());
Notice the use of the eq() argument matcher for matching equality.
see: https://static.javadoc.io/org.mockito/mockito-core/1.10.19/org/mockito/Matchers.html#eq(T)
Also, you could use the same() argument matcher for Class<?> types - this matches same identity, like the == Java operator.
Just in order to complete on the same thread, if someone want to stubb a method that takes a Class as argument, but don't care of the type, or need many type to be stubbed the same way, here is another solution:
private class AnyClassMatcher extends ArgumentMatcher<Class<?>> {
#Override
public boolean matches(final Object argument) {
// We always return true, because we want to acknowledge all class types
return true;
}
}
private Class<?> anyClass() {
return Mockito.argThat(new AnyClassMatcher());
}
and then call
Mockito.when(mock.doIt(this.anyClass())).thenCallRealMethod();
Nice one #Ash. I used your generic class matcher to prepare below.
This can be used if we want to prepare mock of a specific Type.(not instance)
private Class<StreamSource> streamSourceClass() {
return Mockito.argThat(new ArgumentMatcher<Class<StreamSource>>() {
#Override
public boolean matches(Object argument) {
// TODO Auto-generated method stub
return false;
}
});
}
Usage:
Mockito.when(restTemplate.getForObject(Mockito.anyString(),
**streamSourceClass(),**
Mockito.anyObject));
Related
I have this method:
public void validate(param1, pararm2, param3 ...) {
if(check1)
add error
return
if check2
add error
return
getDbObject
check3
exception
return
There is another use case where along with the above checks, if check1 and check2 are passed then after check3 the db object should be returned.
What should be the best practice for implementing this?
Should I write a new method with the same checks and return the db object after check3, or add more parameters and simplify the existing method?
I read the best practice is to have a maximum of 5 parameters, so if we add more parameters eventually the first method call will have 8-9 parameters
and if we reduce the number of parameters then it will require more checks (if-statements) on every call which is also against OOPs basic principles.
So is there an alternate solution?
I would rewrite to use Exceptions, intentionally returning null isn't that helpful to the caller, perhaps like this:
public DbObjectType validate(param1, param2, ...) throws Check1FailedException, Check2FailedException, Check3FailedException {
check1();
check2();
check3();
return getDbObject();
}
private check1() throws Check1FailedException() {
//DoCheck and throw Exception if failed
}
private check2() throws Check2FailedException() {
//DoCheck and throw Exception if failed
}
private check3() throws Check3FailedException() {
//DoCheck and throw Exception if failed
}
I would simply rewrite the method with same amount of parameters and return value of DbObject's type.
Don't really understand what are those checks doing(they check if object's atributes are in range of parameters?..), but i would code something like this:
public DbObjectType validate(param1, param2, ...) {
// if one of the checks fail, validation failed
if (check1 || check2 || ...checkN) {
add error;
return null;
}
else {
DbObject obj = getDbObject();
if (lastCheck) {
exception
return null;
}
return obj;
}
}
You don't have to have every if on separate line, if the actions performed after if are the same for every if. Chaining them together makes the code more readable.
As the return value is DbObject, returning null will not break the program because object types can be null.
You could apply the Strategy Pattern.
Define a ValidationStrategy interface that expose the method public abstract void validate()
Define a class ConcreteValidationA that implements the method validate() with the behaviour of your validate(param1, pararm2, param3 ...)
Define a class ConcreteValidationB that implements the method validate() with the behaviour of the alternative method
In the Context class (i.e. the class where your method stays) add a reference to a ValidationStrategy and modify validate(param1, pararm2, param3 ...) to choose a validation strategy and calling the relative validate() method by forwarding.
Context example
class Context {
/*... your methods and members */
public Context(){
//...
strategy=new ConcreteStrategyA(); //defalut strategy
private ValidationStrategy strategy;
public void validate(int param1, int param2,int param3){
if(param1<param2 && param1<param3)
strategy=new ConcreteStrategyA();
else
strategy=new ConcreteStrategyB();
strategy.validate();
}
}
I'm currently writing unit tests on a code base that uses a lot of ActionEvent's internally, and since ActionEvent doesn't override equals(), I'm creating a custom ArgumentMatcher to match ActionEvent's.
My ArgumentMatcher currently looks like this:
public class ActionEventMatcher extends ArgumentMatcher<ActionEvent> {
private Object source;
private int id;
private String actionCommand;
public ActionEventMatcher(Object source, int id, String actionCommand) {
this.source = source;
this.id = id;
this.actionCommand = actionCommand;
}
#Override
public boolean matches(Object argument) {
if (!(argument instanceof ActionEvent))
return false;
ActionEvent e = (ActionEvent)argument;
return source.equals(e.getSource()) &&
id == e.getId() && actionCommand.equals(e.getActionCommand());
}
}
I would like to know if it possible to change my ArgumentMatcher so that it accepts arguments that were created from other matchers. For instance, if I have a method called actionEvent() that returns the matcher, I would like to be able to do the following:
verify(mock).fireEvent(argThat(actionEvent(same(source), anyInt(), eq("actionCommand"))));
Is there a way to have a custom ArgumentMatcher that accepts arguments from other matchers this way?
You'll be able to do that for Hamcrest or Hamcrest-style matchers, but not for Mockito matchers you get from the static methods on org.mockito.Matchers.
In short, methods like same, anyInt, and eq in Mockito are all designed to fit into method calls in when and verify, so they work counterintuitively through side effects. This makes it really hard to consume them and work with them outside of Mockito internals. By contrast, if you limit yourself to using either Matcher (Hamcrest) or ArgumentMatcher (Mockito) instances, you can manipulate those to your heart's content, and with Hamcrest you'll already have a large library of matchers to start with. See my other Q&A here for context.
In short, your matcher would probably look like this.
public class ActionEventMatcher extends ArgumentMatcher<ActionEvent> {
/* fields here */
public ActionEventMatcher(
Matcher<Object> sourceMatcher,
Matcher<Integer> idMatcher,
Matcher<String> actionCommandMatcher) { /* save fields here */ }
#Override
public boolean matches(Object argument) {
if (!(argument instanceof ActionEvent))
return false;
ActionEvent e = (ActionEvent)argument;
return this.sourceMatcher.matches(e.getSource())
&& this.idMatcher.matches(e.getId())
&& this.actionCommandMatcher.matches(e.getActionCommand());
}
}
As a bonus, you can use describeMismatch in Hamcrest 1.3+ to summarize mismatched fields, which might make it easier to determine which aspects of an ActionEvent are failing. (This won't help for verify calls if you don't use an ArgumentCaptor, though, because Mockito treats a non-matching call as "missing A but received B", not "received B but it failed matcher A for these reasons". You'd have to capture the event and use assertEquals to benefit from mismatch descriptions.)
I am testing a private method using JUnit and I am invoking it using Reflection. The error I am getting is java.lang.InstantiationException. I know it is not creating an instance of Class but I am not sure what I am doing wrong. Object object = clazz.newInstance(); is the line that throws Exception.
Method under test
private int _getType(String type) {
if ("DATE".equalsIgnoreCase(type)) return Types.DATE;
if ("STRING".equalsIgnoreCase(type)) return Types.VARCHAR;
if ("INT".equalsIgnoreCase(type)) return Types.INTEGER;
if ("TIMESTAMP".equalsIgnoreCase(type)) return Types.TIMESTAMP;
return Types.NULL;
}
JUnit test
#Test
public void testGetType() throws Exception {
String type1 = "DATE";
String type2 = "STRING";
String type3 = "INT";
String type4 = "TIMESTAMP";
Class clazz = SpringStoredProcImpl.class;
Object object = clazz.newInstance();
Method method = object.getClass().getDeclaredMethod("getType", String.class);
method.setAccessible(true);
method.invoke(object, type1);
I don't have my asserts yet so please ignore it.
Thanks in advance.
You try to create an instance with a no argument constructor which does exist in your case.
As the constructors are public you should first create your object normally using the new keyword, then execute the rest of your code starting from Method method...
FYI, if you wanted to create your object by reflection it would be something like clazz.getConstructor(DataSource.class, String.class, ArrayList.class).newInstance(dataSource, sprocName, params) instead of simply clazz.newInstance()
Different answer: don't do that.
Why do you think you need to make this method private? It looks like the responsibility of this method is to "lookup" an enum type, based on string input. I think it would make much more sense to simply make this method package protected and avoid the reflection overhead/hassle.
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;
}
}
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.