I am using SpringAMQP where I am testing producer method (basically AMQP template) which is like this.
public void send(Message message, Throwable error, String queue, String routingKey) {
this.amqpTemplate.convertAndSend(
RabbitConfiguration.ERROR_EXCHANGE,
RabbitConfiguration.ERROR_ROUTING_KEY,
message,
messageMetaData -> {
messageMetaData.getMessageProperties().getHeaders().put("x-death-reason", error.getMessage());
return messageMetaData;
}
);
}
I am testing this code with following
import static org.hamcrest.Matchers.any;
....
#Test
public void will_create_error_message_if_incorrect_payload_is_given() {
AmqpTemplate amqpTemplate = mock(AmqpTemplate.class);
Throwable throwable = mock(Throwable.class);
when(throwable.getMessage()).thenReturn("first");
when(throwable.getStackTrace()).thenReturn(null);
ErrorMessageProducer errorMessageProducer = new ErrorMessageProducer(amqpTemplate);
Message message = MessageBuilder.withBody("test".getBytes()).build();
verify(amqpTemplate).convertAndSend(
eq(RabbitConfiguration.ERROR_EXCHANGE),
eq(RabbitConfiguration.ERROR_ROUTING_KEY),
any(Message.class),
Mockito.any()
);
}
But I am getting Invalid use of argument matchers! 4 matchers expected, 3 recorded. Is there any way I can test with Lambda or ignore Lambda altogether.
The problem is because you are using wrong any().
verify(amqpTemplate).convertAndSend(
eq(RabbitConfiguration.ERROR_EXCHANGE),
eq(RabbitConfiguration.ERROR_ROUTING_KEY),
any(Message.class),
Mockito.any()
);
Here your 3rd argument using any from org.hamcrest.Matchers.any, however 4th argument uses right Mockito.any(). So 3rd argument isn't detected as a matcher, but is threated like a usual argument.
To check your lambda you should probably use ArgumentCaptor.
ArgumentCaptor<Runnable> argument = ArgumentCaptor.forClass(Runnable.class);
verify(mock).doSomething(any(), argument.capture());
argument.getValue().run();
...verify that lambda called your services...
You can change Runnable to any type of function your lambda actually represents: i.e. Function/Callable.
Related
I have a function returning an Either<MyError, String> (function2) , which result depends on another function returning another Either<MyError, SomethingElse> (function1)
Both functions rely on a Try block that could fail, and I want to compose those two first function to create a "handle" which will be the main function of my class.
There are basically 3 scenarios possible :
function1 fails : I want handle to return the error given by function1
function1 succeeds and function2 fails : function2 must return its own error then returned by handle
both functions work : handle must return the String
Here is my current code :
private Either<MyError, Path> getPath(Arg arg) { // function 1
return Try.of(() -> //some code that can fail)
.toEither().mapLeft(e -> new MyError("Error message for function1", e));
}
private Either<MyError, String> getContent(Path path) { // function 2
return Try.of(() -> //some code that can fail)
.toEither().mapLeft(e -> new MyError("Error message for function2", e));
}
public Either<MyError, String> handle(Arg arg) {
return Either.right(arg)
.map(this::getPath)
.map(this::getContent);
}
Everything works except the Handle function, I think that my problem might be related to the use of Either::map function, that might not be the thing for my case.
Any thought about this ?
Also, sorry if the answer seems obvious, i am quite new to functionnal programming and vavr.
The method that could help to make this work would be flatMap.
So if you use flatMap instead of map, the handle method will become something like:
public Either<MyError, String> handle(Arg arg) {
return Either.<MyError, Arg>right(arg)
.flatMap(this::getPath)
.flatMap(this::getContent);
}
The scenarios you mentioned are all covered with this flatMap method.
See the Either.flatMap documentation for the official docs about it.
I have a method which accepts Mono as a param.
All I want is to get the actual String from it. Googled but didn't find answer except calling block() over Mono object but it will make a blocking call so want to avoid using block(). Please suggest other way if possible.
The reason why I need this String is because inside this method I need to call another method say print() with the actual String value.
I understand this is easy but I am new to reactive programming.
Code:
public String getValue(Mono<String> monoString) {
// How to get actual String from param monoString
// and call print(String) method
}
public void print(String str) {
System.out.println(str);
}
Getting a String from a Mono<String> without a blocking call isn't easy, it's impossible. By definition. If the String isn't available yet (which Mono<String> allows), you can't get it except by waiting until it comes in and that's exactly what blocking is.
Instead of "getting a String" you subscribe to the Mono and the Subscriber you pass will get the String when it becomes available (maybe immediately). E.g.
myMono.subscribe(
value -> System.out.println(value),
error -> error.printStackTrace(),
() -> System.out.println("completed without a value")
)
will print the value or error produced by myMono (type of value is String, type of error is Throwable). At https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html you can see other variants of subscribe too.
According to the doc you can do:
String getValue(Mono<String> mono) {
return mono.block();
}
be aware of the blocking call
Finally what worked for me is calling flatMap method like below:
public void getValue(Mono<String> monoString)
{
monoString.flatMap(this::print);
}
What worked for me was the following:
monoString.subscribe(this::print);
Simplest answer is:
String returnVal = mono.block();
This should work
String str = monoString.toProcessor().block();
Better
monoUser.map(User::getId)
I am trying to wrap methods which throws checked exceptions.. I am following steps told in this url: https://www.rainerhahnekamp.com/en/ignoring-exceptions-in-java/
Interestingly when I write the code like this:
IntStream.range(1, locales.length)
.mapToObj(i -> locales[i].toString())
.forEach(wrap(this::testLocale));
it is working fine but when I write like this:
IntStream.range(1, locales.length)
.mapToObj(i -> locales[i].toString())
.forEach(s -> wrap(testLocale(s)));
Intellij is complaining "Unhandled Exception: java.lang.Exception"
here testLocale looks like this:
void testLocale(String s) throws Exception
The wrap function looks like this:
public static <T> Consumer<T> wrap(WrapConsumer<T> wrapper) {
return t -> {
try {
wrapper.accept(t);
} catch(Exception exception) {
throw new RuntimeException(exception);
}
};
}
and WrapConsumer is a function interface with Consumer signature:
#FunctionalInterface
public interface WrapConsumer<T> {
void accept(T t) throws Exception;
}
I am banging my head trying to understand why Intellij is complaining based on how I write the lambda
You are supposed to provide a wrapped consumer to forEach via:
.forEach(wrap(this::testLocale));
what you are doing via s -> wrap(testLocale(s)) is provide a new consumer that still can't handle the checked Exception.
Probably simpler to understand would be that forEach accepts a Consumer that has a method definition of:
void accept(T t); // does not define to throw the checked Exception
When you do forEach(s -> ...), it is this Consumer::accept that you are using.
On the other hand that forEach(wrap(this::testLocale)); will return a Consumer still, but by accepting as input a WrapConsumer<T> wrapper that does declare to throw that Exception via:
void accept(T t) throws Exception;
You're just missing the correct lambda syntax. Your current code is calling wrap with a void argument: wrap(testLocale(s)) - (testLocale(s) has a void return type)
The correct lambda expression that you need is:
.forEach(wrap(s -> testLocale(s)));
wrap returns a function, so you don't need delayed execution for it (i.e., no need for a function that calls wrap).
Just complementing what Eugene answered, you are expecting with the method wrap() a consumer as param, not a invocation method returning void.
You can prove this by removing the throws Exception from the testLocale method.
The IDE will them give you the error:
"reason: no instance(s) of type variable(s) T exist so that void conforms to WrapConsumer<T>"
The similar code for the one you wrote (right consumer):
IntStream.range(1, locales.length)
.mapToObj(i -> locales[i].toString())
.forEach(wrap(this::testLocale));
Would be:
IntStream.range(1, locales.length)
.mapToObj(i -> locales[i].toString())
.forEach(wrap(l-> testLocale(l)));
Scenario is an interface of Cucumeber.api package.
I want to use this interface to get scenario name.
I am trying:
String string = () - > {
public String getName(Scenario scenario) {
return scenario.getName().toString();
}
});
but it is giving error, what am I missing here?
I am already following several posts (like below), but didn't what wrong I am doing:
Lambda Expression is not working, getting terminated
I am using a series of Strict Mocks generated with EasyMock 3.2 to test a method that call's itself recursively. By setting the expectations of my mocks I can control the method so that it only calls itself once and then exits. However, I am seeing some very strange behaviour from EasyMock which looks like a bug, where it get's confused about the number of times a method is expected.
For example:
final Collection srcCollection = EasyMock.createStrictMock(Collection.class);
final NativeBroker broker = EasyMock.createMockBuilder(NativeBroker.class)
.addMockedMethod("getCollection")
.addMockedMethod("getSubject")
.createStrictMock();
expect(srcCollection.getURI()).andReturn(src);
replay(srcCollection, broker);
//run the test
broker.checkPermissionsForCopy(srcCollection, dest, newName);
verify(srcCollection, broker);
Leads to the error from EasyMock:
java.lang.AssertionError:
Expectation failure on verify:
Collection.getURI(): expected: 2, actual: 1
at org.easymock.internal.MocksControl.verify(MocksControl.java:226)
at org.easymock.EasyMock.verify(EasyMock.java:2080)
I have only instructed EasyMock to expect one result, so why does it think I want two? I also get the same error if I change my expectation to this:
expect(srcCollection.getURI()).andReturn(src).once();
...And it get's stranger...
If I change my expectation to this:
expect(srcCollection.getURI()).andReturn(src).times(2);
I get the error:
java.lang.AssertionError:
Expectation failure on verify:
Collection.getURI(): expected: 3, actual: 1
at org.easymock.internal.MocksControl.verify(MocksControl.java:226)
at org.easymock.EasyMock.verify(EasyMock.java:2080)
And, further if I change my expectation to this:
expect(srcCollection.getURI()).andReturn(src).anyTimes();
I get an even stranger error:
java.lang.IllegalStateException: last method called on mock already has a non-fixed count set.
at org.easymock.internal.MocksControl.replay(MocksControl.java:216)
at org.easymock.EasyMock.replay(EasyMock.java:2012)
Does anyone have any suggestions, or know of any limitations with EasyMock in recursive functions?
In my case I repeated same expected values 2 times. And it throws:
java.lang.IllegalStateException: last method called on mock already has a non-fixed count set.
E.G.
SchedulingDataForVersion dataForVersion = createNiceMock(SchedulingDataForVersion.class);
TaskSource mockedTaskSource = createNiceMock(TaskSource.class);
expect(mockedTaskSource.getOrderElement()).andReturn(orderLine).anyTimes();
expect(mockedTaskSource.getOrderElement()).andReturn(orderLine).anyTimes();
replay(dataForVersion, mockedTaskSource);
Correct one is:
SchedulingDataForVersion dataForVersion = createNiceMock(SchedulingDataForVersion.class);
TaskSource mockedTaskSource = createNiceMock(TaskSource.class);
expect(dataForVersion.getOrderElement()).andReturn(orderLine).anyTimes();
expect(mockedTaskSource.getOrderElement()).andReturn(orderLine).anyTimes();
replay(dataForVersion, mockedTaskSource
The error occurs when you add .anyTimes() and then you write the same call.
expect(mock.get()).andReturn("string").anyTimes(); --> first call with multiple support
expect(mock.get()).andReturn("string"); --> second call not needed
The solution is to write only the first call with multiple support
expect(mock.get()).andReturn("string").anyTimes();
I can't see anything wrong with this code.
Are the two mocked methods on the broker expected not to be called?
I made a test case. Can you make it fail?
public class AppTest {
public static interface Collection {
String getURI();
}
public static class NativeBroker {
public void checkPermissionsForCopy(Collection srcCollection, String dest,
String newName) {
srcCollection.getURI();
}
public Collection getCollection() {
return null;
}
public String getSubject() {
return null;
}
}
String src = "http://src.com";
String dest = "http://dest.com";
String newName = "my name";
#Test
public void testApp() {
final Collection srcCollection = EasyMock.createStrictMock(Collection.class);
final NativeBroker broker = EasyMock.createMockBuilder(NativeBroker.class)
.addMockedMethod("getCollection")
.addMockedMethod("getSubject")
.createStrictMock();
expect(srcCollection.getURI()).andReturn(src);
replay(srcCollection, broker);
// run the test
broker.checkPermissionsForCopy(srcCollection, dest, newName);
verify(srcCollection, broker);
}}