I have issue where when I use Java parallelStream instead of stream my tests fail. This happens because I am returning Mock objects in a strict order rather than controlling Mock objects returned based on input.
The following is my current code used to return mocks objects:
when(myOperation.getSomething(any(String.class)))
.thenAnswer(AdditionalAnswers.returnsElementsOf(aListOfThings)));
How can I concisely control the return value based off the argument I am passing to "getSomething"?
You can do something like that:
when(myOperation.getSomething(any(String.class))).thenAnswer(new Answer<SomeThing>() {
#Override
public SomeThing answer(final InvocationOnMock invocation) throws Throwable {
// HERE ====> use invocation.getArguments()
return new SomeThing();
}
});
Here the answer return a SomeThing instance, you will need to adjust to your needs
Some reading:
Java 8 custom answer support
doAnswer documentation
InvocationOnMock javadoc
Instead of using an Answer, you can just iterate across your values and set up specific stubs for each one. Unlike with an Answer, you have to be able to predict all values for which you're stubbed, but for your particular case here it sounds like that might not be a problem.
for (int i = 0; i < aListOfThings.size(); i++) {
when(myOperation.getSomething(aListOfKeys.get(i)))
.thenReturn(aListOfThings.get(i));
}
Related
There are so many questions and threads about Optional API but I didn't found any for my case.
For example, I need first check emptiness of an Optional variable, for logging purpose, and then
check the value, if presents, with some predicate. Whatever check fails, I need to throw an exception.
Below is my real workaround for that
SomeValue value = someOptional.orElseThrow(() -> {
log.debug("nothing here");
return new NothingSpecialHereException();
});
if (!value.isSpecial()) {
log.debug("something here, but not special");
throw new NothingSpecialHereException();
}
When I was looking for an alternative solution for that, I tried something like that
SomeValue value = someOptional
.filter(SomeValue::isSpecial)
.orElseThrow(() -> {
log.debug("nothing special here"); // but this case for both "no value" and "value is not special"
return new NothingSpecialHereException();
});
I know that there's no any built-in solution for this situation in Java, but seems like I missing something like:
SomeValue value = someOptional
.ifNotPresent(() -> log.debug("nothing here")) // that method returns Optional for further invocatons
.filter(val -> {
if (!val.isSpecial()) {
log.debug("something here, but not special");
return false;
}
return true;
})
.orElseThrow(NothingSpecialHereException::new);
This is not the first time when I miss something like ifNotPresent or else* methods for use in the middle of pipe, not in the end. IMO sometimes that approach might be more readable, for example
optional
.map(...)
.filter(...)
.ifEmpty(...) // do smth after filter, maybe even throw
.map(...) // and continue processing
Maybe anyone encountered same problem? Or maybe I missed some better solution? Maybe there's a library that provides solutions for that?
The JDK Optional includes (since Java 9 only, which was a major oversight in Java 8) ifPresentOrElse, which could be used with a no-op first argument. Alternately, the Vavr library is a set of functional wrappers that is slightly more consistent than Optional and provides additional useful wrappers such as Try at the cost of having an extra dependency.
SomeValue value = Optional.ofNullable(someValue.isPresent()?
someValue.filter(SomeValue::isSpecial)
.orElseThrow(NothingSpecialHereException::new)
:null)
.orElseThrow(NothingHereException::new) ;
If someValue is present then the value can be set to special value or throw exception NothingSpecialHereException else if someValue is not present it will give Optinal it will check if null (someValue is not present) Throw NothingHereException.
Exception "NothingSpecialHereException" thrown only if value is present and not special.
Exception "NothingHereException" thrown only if value is not present.
Thanks to comments! I've checked out Vavr Option and Guava Optional APIs.
Guava Optional is even less rich in methods than Java Optional, so this is not a solution.
What I've found is the Vavr onEmpty method of Option class, that executes Runnable if the Option value is empty.
SomeValue value = Option.ofOptional(someOptional)
.onEmpty(() -> log.debug("nothing here"))
.filter(val -> {
if (!val.isSpecial()) {
log.debug("something here, but not special");
return false;
}
return true;
})
.getOrElseThrow(NothingHereException::new);
That example displays one of debug messages and throws exception only in one place. Looks a lot better.
However, Vavr is a big library with own collections, functional interfaces and monads like above. This is a big dependency for a project and it is hardly will be implemented in my project or any other long-time-existed project just for new fancy Optional replacement.
Plus, Vavr's Option does'nt have something like onEmptyThrow, so it's not so perfect =).
This thread is still open for suggestions, but now for Java 8 workaround I think this comment may be considered as answer.
UPDATE
Seems like I've found the best solution for problems like that.
Few days ago I found lombok's #ExtensionMethod annotation that makes possible solutions like below
class Extensions {
public static <T, E extends Throwable> Optional<T> ifNotPresentThrow(Optional<T> opt, Supplier<E> exceptionSupplier) throws E {
if (!opt.isPresent()) {
throw exceptionSupplier.get();
}
return opt;
}
}
#ExtensionMethod(Extensions.class)
class Test {
public static void main(String[] args) {
// assume there is someNullable variable
// instead of writing
Extensions.ifNotPresentThrow(Optional.ofNullable(someNullable), NothingHereException::new)
.map(...);
// I can write
Optional.ofNullable(someNullable)
.ifNotPresentThrow(NothingHereException::new)
.map(...); // now possible to continue if optional present
}
}
With that Kotlin-like extension methods it's possible to add any method to Optional's API. Lombok will just transform second variant into first during compilation.
However, this feature is experimental (seems like forever) and has possible bugs and decompiled bytecode looks pretty dirty (with various unnecessary local variables, etc.)
I have a method signature like
public void add(byte[] key, Optional<Byte[]> secondaryKey) { ... }
My test looks something like
byte[] key = "testKey".getBytes();
byte[] secondaryKey = "secondaryKey".getBytes()
//call the method that internally calls add()
Mockito.verify(mockClass).add(key, Optional.of(ArrayUtils.toObject(secondaryKey))
The verification always fails in this case saying wanted parameters are different from actual. I have a similar add method that just take byte[] key as input parameter. Test on that method succeeds. So I think there is something wrong with the way I am trying to match Optional parameter here.
The Optional does not perform a deepEquals, therefore the equality check will fail considering that you have passed an Byte[] into the Optional.
You can see this bug report from a user that faced a similar issue. JDK-8075723
You will probably want to leverage some ArgumentMatchers to compare the arguments passed into your mock.
Since you have an Optional being passed through, you can unwrap that object using ArgumentMatchers.argThat which requires you to implement a ArgumentMatcher.matches method.
Mockito.verify(mockClass).add(ArgumentMatchers.eq(key), ArgumentMatchers.argThat(r -> {
return r.isPresent() && Objects.deepEquals(secondaryKey, r.get())
));
Edit:
You can also use ArgumentCaptor if you prefer to capture the state of the parameters passed into the mocks and perform assertions.
ArgumentCaptor<Optional> captor =ArgumentCaptor.forClass(Optional.class)
verify(pojo).add(eq(key), captor.capture());
Optional<byte[]> result = captor.getValue();
assertTrue(result.isPresent());
assertArrayEquals(secondaryKey, result.get());
I want to use mockito spy.
When I set a return value in both following ways:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate));
doReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate)).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
I see the return value is being evaluated eagerly
meaning when this "setting" line is executed.
how can i force the spy to evaluate the return value only on demand?
meaning when the "when" condition is met.
update
Thanks to #RobbyCornelissen I have tried this code:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
ImagesSorter mock = (ImagesSorter)invocation.getMock();
return mock.sortImages((List<Image>)args[0], (UserInfo)args[1], fakeNowDate);
}
});
But it didn't help:
1) the "when" expression was invoked immediately. (not wanted)
2) eventually the callback wasn't call.
First let me warn you on partial mocks, because that is what the code is actually doing, it's wrong design wise. It may be more relevant to use a strategy pattern to compose behavior of the tested subject. Mockito team (including me) strongly advises to stay away of partial mocks whenever possible.
EDIT : I don't know the code and I don't know exactly which component under test but from what I gather there's a type responsible to sort images, let's call it ImagesSorter.
So first case ImagesSorter is a dependency of a test subject, so in this case just stubbing the mock of ImagesSorter will do.
If however it is ImagesSorter itself under test, and stubbing a special method of this class is called a partial mock and it is plain wrong. It exposes internal of the production code in the test. So there's several solutions.
As the code snippet showed in the answer shows a fakeDate, one of the solution is to not use things like new Date() and code a simple class TimeSource whose sole responsibility is to provide a date. And in tests the bwhavior of this TimeSOurce could be overriden.
A simplier solution would be to use JodaTime as it provides this functionality built in.
If the scope of test goes beyond changing the date, then maybe ImagesSorter needs a way to be configured with other objects. Inspiration on how to do it can be found with the cache builder of guava. If the configuration is dead simple then a simple constructor coud do it.
That could look like :
class ImagesSorter {
ImagesSorterAlso algo;
ImagesSorter(ImagesSorterAlgo algo) { this.algo = algo; }
Iterable sortImages(...) {
algo.sort(...);
}
}
interface ImagesSorterAlgo {
Iterable sort(...);
}
Now about your questions :
1) the "when" expression was invoked immediately. (not wanted)
It is expected imagesSorterSpy is a spy so by default it calls the real code. Instead you should use the alternate API, the same that #RobbyCornelissen showed. i.e.
doAnswer(sortWithFakeDate()).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
// with BDD aliases (BDDMockito) which I personnaly finds better
willAnswer(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
will(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
sortWithFakeDate() would a static factory method that returns the answer, so the code reads well, and maybe reused elsewhere.
2) eventually the callback wasn't call.
This issue is most probably due to non equal arguments. You may need to check the equals method. Or relax the stub using the any() matcher.
I don't know the types of the arguments and classes you're using, so I can't provide a complete example, but you can stub using callbacks with the Answer<T> interface:
Mockito.doAnswer(new Answer() {
Object answer(InvocationOnMock invocation) {
ImagesSorter mock = (ImagesSorter) invocation.getMock();
Object[] args = invocation.getArguments();
return mock.sortImages((List<Image>) args[0], (UserInfo) args[1],
fakeNowDate);
}
}).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
The Java OpenGL GL interface contains about 2000 methods, for debugging purposes I would like to wrap an instance and delegate calls to it while doing some logging. The logging code can be pushed to the same method in each case, so the task of writing out the method implementations looks like it could be automated. An example of what I am trying to do:
import javax.media.opengl.GL;
public class GLErrorLogger implements GL {
private final GL backing;
public GLErrorLogger(GL delegateToMe) {
backing = delegateToMe;
}
private void checkErrorCode() {
// Log frame and thread details depending on gl state
}
/**
* Example of a method
*/
#Override
public int glGenLists(int arg0) {
checkErrorCode();
int retVal = backing.glGenLists(arg0);
checkErrorCode();
return retVal;
}
// rest of methods here...
}
In other words copy the method name and parameters (minus their types) into a call on the backing object, surround with calls to the logging method, and if there is a return type then assign the result to a variable of this type and return it at the end of the method.
I looked at creating a one shot eclipse code template to autogenerate the methods, but there wasn't an immediately obvious way to do pattern matching on the return type. Can anyone suggest a way to do this in Eclipse or any of its code generation tools to save me pulling out the regex toolkit?
You might want to use an Aspect to create the necessary bytecode for you instead of producing all the source code. Take a look at the Traceing Aspect example here: Traceing Aspect Example.
As an Alternative, you can create a Java Dynamic Proxy, if you do not want to use AspectJ as Thrid party Library. Please refer to Dynamic Proxy Tutorial
Use JDK proxies as suggested, or: use a Mock Framework like EasyMock or Mockito.
GL mock = EasyMock.createMock(GL.class);
EasyMock.expect(mock.someMethod()).andReturn(someValue);
// or, if you need to do more computing:
EasyMock.expect(mock.someOtherMethod()).andAnswer(new IAnswer<String>() {
public String answer() throws Throwable {
return "some value you calculate here";
}
});
EasyMock.replay(mock);
now you can use the mock Object for all methods you configured.
See the EasyMock readme for more info.
It's a simple and maybe trivial question: in Java how can I iterate through the parameters passed to the method where I'm working?
I need it to trim() all of them that are strings.
EDIT
To be more precise an example of use can be this (written in a pseudo-code reflecting how I wish it to work):
public void methodName(String arg1, int arg2, int arg3, String arg4, double arg5)
for(Object obj : getThisMethod().getParameters() )
System.out.println(obj.getName() + " = " + obj.toString())
The point is that getThisMethod().getParameters(). What must I write in that place?
If your function uses Varargs this is pretty straightforward:
private void yourFunction(String... parameters) {
for (String parameter : parameters) {
// Do something with parameter
}
}
Individual parameters aren't iterable; you'd need a collection for that.
You'll just have to get a shovel if they're individual Strings.
If you have so many String parameters that this is oppressive, perhaps your method needs to be re-thought. Either all those parameters should be encapsulated into an object, because they're related, or that method is trying to do too much. It speaks to a lack of cohesion to me.
The task you are trying solve is only possible using AOP (Aspect Oriented Programming) frameworks.
AOP frameworks allow you to add some code to the method without changing it. In reality they create Proxy classes that wrap around your original classes and execute required lines of code before each method you bind them too.
However, AOP is an overkill for some simple tasks as it usually requires some complex configurations and usually integration with DI frameworks.
Here's some list of AOP frameworks if you are still interested: http://java-source.net/open-source/aspect-oriented-frameworks.
Edit:
Actually, I think that you are doing your task the wrong way in first place. If your method is a part of Business Layer - it should not allow non-trimmed parameters and throw some kind of Exception in that case. If your method is part of some Presentation Layer - it should be cleaning the parameters manually, usually near the part where it reads the parameters from the user.
For example, if you are reading that parameters from some Swing form, then you should trim them before passing to your Constructor. For example:
Your current code:
int someId = Integer.valueOf(idField.getText());
String someName = nameField.getText();
String someArg = argField.getText();
new Constructor(someId, someName, someArg)
How it should be handled:
int someId = Integer.valueOf(idField.getText());
String someName = nameField.getText().trim();
String someArg = argField.getText().trim();
new Constructor(someId, someName, someArg)
For you can change your method to be the following you can iterate over them.
public void method(String... args)
If your question is how to recognise a String from an Object, you can do that:
if (myObject instanceof String) {
// My param is a string!
}