Stubbing #Async method run as sync - java

I am trying to test async method with timeout.
When I am calling the method directly the method run asynchronically and throw TimeoutException as expected. But when I stub the method, the method run synchronically and TimeoutException is not thrown. What am i doing wrong?
Class A()
{
#Async
public Future<Integer> asyncMethod(){
Thread.sleep(5000);
return new AsyncResult<>(1);
}
}
Class B()
{
A a;
#Autowired
B(A a)
{
this.a=a;
}
public void syncMethod()
{
Future<Integer> futureResult = a.asyncMehod();
// 2sec < 5sec, expect to throw TimeoutException
futureCount.get(2, TimeUnit.SECONDS);
}
}
Class TestBMockBean()
{
#MockBean
A a;
B b;
#BeforeAll
public void init()}{
this.b = new B(a);
}
// This test failed
#Test
void syncMethod() {
when(a.asyncMethod()).thenAnswer((Answer<AsyncResult<Integer>>) invocation -> {
Thread.sleep(5000);
return new AsyncResult<>(0);
});
}
assertThrows(TimeoutException.class,()-> b.syncMethod());
}
}
Class TestBAutowired()
{
#Autowired
B b:
// This test pass
#Test //success
void syncMethod_autowired() {
assertThrows(TimeoutException.class,()-> b.syncMethod());
}
}

Related

Mocking/skipping sleep calls in unit tests

What is the general approach in unit tests for methods that involve a sleep() call?
Lets say I have the class:
class Foo {
public bool someMethodWithSleep() {
bool failed = false;
for (int i = 0 : 5) {
failed = trySomething(); // mocked to return false
if (failed) {
TimeUnit.SECONDS.sleep(5);
} else { return true; }
}
return false;
}
}
In test cases for failures that call this function (directly or nested), I dont want it to sleep for 25+ seconds and slowing every test file that calls it. What's the best approach to skip the sleep calls in unit tests?
Replace it with a dependency.
class Foo {
private final Sleeper sleeper;
public Foo(final Sleeper sleeper) {
this.sleeper = sleeper;
}
public Foo() {
this(SecondsSleeper.INSTANCE);
}
public bool someMethodWithSleep() {
bool failed = false;
for (int i = 0 : 5) {
failed = trySomething(); // mocked to return false
if (failed) {
sleeper.sleep(5);
} else { return true; }
}
return false;
}
}
interface Sleeper {
void sleep(int duration);
}
enum SecondsSleeper implements Sleeper {
INSTANCE;
void sleep(final int seconds) {
TimeUnit.SECONDS.sleep(seconds);
}
}
enum TestSleeper implements Sleeper {
INSTANCE;
void sleepSeconds(final int duration) {
// do nothing
}
}
Then in your real application, create Foo as new Foo() and in your test as new Foo(TestSleeper.INSTANCE)

Mockito doReturn() executes the Real function instead of just return

I'm trying to mock Class D constructor. yet, the mocked objects invokes the real function instead of just returning the value.
Read from bottom.
Main
public abstract class F
{
int hi()
{
throw new Exception("I always throw Exception. So don't execute me");
return 1;
}
}
public abstract class E extends F
{
int hi()
{
return super.hi();
}
}
public class D extends E
{
}
public class C
{
D d_object;
C()
{
d_object = new new D(); // will be mocked_d!
}
int hi()
{
d_object.hi();
}
}
public class B
{
void fun()
{
C object = new C();
int value = object.hi();
}`
}
Test
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJunit4ClassRunner.class)
#PrepareForTest({C.class,D.class})
public class Test_B
{
#Autowired
A o_A;
#Test
public void test_method()
{
D mocked_D = mock(D.class);
PowerMockito.whenNew(D.class).withNoArguments().then(new Answer()
{
#Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
return mocked_D;
}
});
PowerMockito.doReturn(2).when(mocked_d).hi();
Assert.assertEquals(2,o_A.fun()) // throws Exception. since method inside class F gets executed.
}
}
hi() method inside class F always gets invoked, hence it throws execution. I don't want to invoke that function. am I doing anything wrong?
When using #PrepareForTest I always use PowerMockito.mockStatic method inside tests.

How can I create unit test for void method with try...catch inside?

I create simple service for example:
public class MyService {
public void process() {
try {
CustomerMessagesService customerMessagesService = new CustomerMessagesService();
String message = customerMessagesService.getMessage();
// another logic which can throw an exception
SpamCenterService spamCenterService = new SpamCenterService();
spamCenterService.sendAdvertise(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
This service calls from Scheduler each 1 second.
customerMessagesService return message with an advertisement text or throw an exception if this message contains illegal text. If customerMessagesService return success text - it to send to spamCenterService and if customerMessagesService throw an exception - it exception just logged. There is another logic which can throw exception between calls of these services. This exception logs too.
Now I want to create a unit test for this method. But I don't understand how to test the void method with try..catch block.
I create this:
public class MyServiceTest {
private MyService myService;
#Before
public void setUp() {
myService = new MyService();
}
#Test
public void process() {
myService.process();
}
}
But it is always a success because the process method doesn't throw exceptions.
How can I test this method?
EDIT
I find one solution but I am not sure about it.
public class MyServiceImpl implements MyService {
public void process() {
try {
doIt();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doIt() throws Exception {
CustomerMessagesService customerMessagesService = new CustomerMessagesService();
String message = customerMessagesService.getMessage();
// another logic which can throw an exception
SpamCenterService spamCenterService = new SpamCenterService();
spamCenterService.sendAdvertise(message);
}
}
And test doIt() method in MyServiceImpl.
In short do the following:
Move object creation out of your method
Create mocks (with e.g. Mockito) and inject those
verify that the mocks were used as expected
A concrete example below:
public class MyService {
private CustomerMessagesService customerMessagesService;
private SpamCenterService spamCenterService;
//inject dependencies
public MyService(CustomerMessagesService customerMessagesService, SpamCenterService spamCenterService) {
this.customerMessagesService = customerMessagesService;
this.spamCenterService = spamCenterService;
}
public void process() {
try {
String message = customerMessagesService.getMessage();
// another logic which can throw an exception
spamCenterService.sendAdvertise(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class MyServiceTest {
private MyService myService;
// mock dependencies with Mockito
private CustomerMessagesService customerMessagesService = Mockito.mock(CustomerMessagesService.class);
private SpamCenterService spamCenterService = Mockito.mock(SpamCenterService.class);
#Before
public void setUp() {
myService = new MyService(customerMessagesService, spamCenterService);
}
#Test
public void process() {
myService.process();
Mockito.verify(customerMessagesService).getMessage();
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
Mockito.verify(spamCenterService).sendAdvertise(messageCaptor.capture());
assertThat(messageCaptor.getValue(), is(nullValue()));
}
#Test
public void processWithSpecificCustomerMessageServiceBehaviour() {
Mockito.given(customerMessagesService.getMessage()).willReturn("expectedString");
myService.process();
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
Mockito.verify(spamCenterService).sendAdvertise(messageCaptor.capture());
assertThat(messageCaptor.getValue(), is("expectedString"));
}
#Test
public void processCatchExceptions() {
Mockito.given(customerMessagesService.getMessage()).willThrow(new Exception("Bad message"));
myService.process();
// if exception is thrown then the code should not reach spamCenterService.sendAdvertise()
Mockito.verify(spamCenterService, Mockito.never()).sendAdvertise(Mockito.anyString());
}
}
Note that you can also setup mocks to throw specific exceptions or return specific values so that you can test all possible scenarios.

Wait for method which return DeferredResult

I have service method which return DefferedResult<Foo> in few seconds, but I need my code will wait until that method finish and return deferred result with set result.
Here is sample code:
#Service
public class FooService {
// ...
public DeferredResult<Foo> fetchFoo(long id) throws InterruptedException {
DeferredResult<Foo> fooDeferredResult = new DeferredResult<>();
concurrentMap.put(id, fooDeferredResult);
return fooDeferredResult;
}
// this you can figure out as some handler or scheduler which receive messages and is called
public void anotherMethod(Foo foo) {
DeferredResult<Foo> remove = concurrentMap.remove(foo.getId());
remove.setResult(foo);
}
// ...
}
and I want call it in another service:
#Service
public class AnotherService {
#Autowired
FooService fooService;
public Foo bar(long id) {
// some logic
Foo foo = fooService.fetchFoo(id).getResult();
// another logic which depends on received foo
// there I need wait for result of fetchFoo method
return foo;
}
}
Can you tell me please how to ensure this behaviour? Thank you in advice.
You can use CountDownLatch for synchronize. Example:
public class Main {
public static void main(String[] args) throws InterruptedException {
System.out.println(1);
CountDownLatch latch = new CountDownLatch(1);
getResult()
.setResultHandler(result -> {
System.out.println(2 + " " + result);
latch.countDown();
});
latch.await();
System.out.println(3);
}
public static DeferredResult<String> getResult() {
DeferredResult<String> result = new DeferredResult<>();
new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
result.setResult("Hello");
})
.start();
return result;
}
}

Mocking a Java object across classes/methods

I am using Mockito/PowerMockito APIs to mock some objects for junit cases.
In the example given below, I want to create a mock object of class C (returned by Utils.getC()). Also I want to use same mock object of C in B.execute(), and not a new object. Is there a way I can achieve this? Please help. [Update - Thanks Lino for answering this. I have edited the code given below.]
However, this works for static methods only. I am not able to mock instance method D.displayMessage() (invoked from A.execute() and B.execute()).
#PrepareForTest(mock.Utils.class)
#RunWith(PowerMockRunner.class)
public class TestMock {
private static C c;
private static D d;
#BeforeClass
public static void runOnceBeforeClass() {
try {
System.out.println("#BeforeClass - runOnceBeforeClass");
PowerMockito.mockStatic(Utils.class);
c = Mockito.mock(C.class);
System.out.println("c = " + c);
PowerMockito.doReturn("Hello!!").when(c).displayMessage();
Answer<Void> answer = new Answer() {
public Void answer(InvocationOnMock invocation) {
System.out.println("I can perform!");
return null;
}
};
PowerMockito.doAnswer(answer).when(c).perform();
PowerMockito.when(Utils.getC()).thenReturn(c);
Answer<Void> answer1 = new Answer() {
public Void answer(InvocationOnMock invocation) {
System.out.println("I can utilize!");
return null;
}
};
PowerMockito.doAnswer(answer1).when(Utils.class);
Utils.utilize();
Answer<Void> answer2 = new Answer() {
public String answer(InvocationOnMock invocation) {
System.out.println("I can run with params!");
return null;
}
};
PowerMockito.doAnswer(answer2).when(Utils.class);
Utils.runWithParams(Mockito.anyString(), Mockito.anyInt(), Mockito.any());
d = PowerMockito.mock(D.class);
PowerMockito.when(d.displayMessage()).thenReturn("D: I can display!");
PowerMockito.whenNew(D.class).withNoArguments().thenReturn(d);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#AfterClass
public static void runOnceAfterClass() {
System.out.println("#AfterClass - runOnceAfterClass");
}
#Before
public void runBeforeTestMethod() {
System.out.println("#After - runBeforeTestMethod");
}
#After
public void runAfterTestMethod() {
System.out.println("#After - runAfterTestMethod");
}
#Test
public void testExecution() {
System.out.println(Utils.getC().displayMessage());
A a = new A();
a.execute();
}
}
class A {
public void execute() {
System.out.println("executing A");
B b = new B();
b.execute();
System.out.println(new D().displayMessage());
}
}
class B {
public void execute() {
System.out.println("executing B");
C c1 = Utils.getC();
System.out.println("c = " + c1.hashCode());
c1.perform();
Utils.utilize();
Utils.runWithParams("", 3, "2");
System.out.println(new D().displayMessage());
}
}
class C {
public String displayMessage() {
return "C: I can't display.";
}
public void perform() {
System.out.println("I can't perform.");
}
}
class D {
public String displayMessage() {
return "D: I can't display.";
}
}
class Utils {
public static C getC() {
return null;
}
public static void utilize() {
System.out.println("I can't unitilize.");
}
public static String runWithParams(String s, Integer i, Object o) {
System.out.println("I can't run with params.");
return "abc";
}
}
If you are trying to reuse the mocked object of C, for the static method call inside execute() method of B , the same mocked object can be reused.

Categories

Resources