How can I write a unit test for this asynchronous method? - java

When I write unit tests for business code, I need to mock asynchronous thread calls and return a simulated result to save in the database. I don't know how to write unit test code for this method.
The tested code is as follows:
public void doWork(){
ExecutorService executor = Executors.newSingleThreadExecutor();
FutureTask<TestVO> futureResult = null;
futureResult = new FutureTask<TestVO>(new Callable<TestVO>() {
public TestVO call() {
return testService.scan(_scan_params, finalProcess, _ywid, _logPath);
}
});
executor.execute(futureResult);
TestVO testVO = futureResult.get(0, TimeUnit.SECONDS);
TestRepository.save(testVO);
}
The method that needs to be mocked is as follows:
#Async("taskAccStepExecutor")
public TestVO scan(String params, String process, String ywid, String LogPath) {
......
return testVO;
}
I used testng/mokito as a testing framework in my project.
My expectation is to simulate an asynchronous thread and return a custom testVO. This problem has troubled me for several days and I hope to get your help.

Working on the assumption that the class that defines the doWork() method (let's call that class "Worker") gets the "testService" injected somehow and you have control over how that gets injected.
In that case, it would likely suffice if you create a Worker with a mocked testService in your unit test. Add when(testService.scan(anyString(), anyString(), anyString(), anyString()).thenReturn(new TestVO()) to mock what you are expecting from the service.
Then call the doWork method as that seems to be the method that you want to test.
Then verify that the scan method was called: verify(testService).scan(anyString(), anyString(), anyString(), anyString()).
Maybe also validate that the TestVO object was saved to your database.

Related

Make Mocked Static Methods Available for All Threads (or at least subthreads)

I have the following code that I want to test using Junit5
public void myMethod() {
final ExecutorService executor = ThreadsUtils.newFixedThreadPool();
executor.submit(() -> {
ClassWithStaticMethod.staticMethod();
})
}
I wrote the the following test case
try (MockedStatic<ClassWithStaticMethod> mockedStatic = mockStatic(ClassWithStaticMethod.class)) {
...
someObject.myMethod(COUNTRY_CODE);
...
}
The above mocking does not work as per the the docs of mockStatic, the mocked static method's scope is only the current thread. However, how can we mock static method for multiple-threads scenario?

In JUnit with Mockito, how can I wait for an asynchronous method to complete?

I am writing an integration test against some code that asynchronously creates a record when a different value is updated in the database. I would like to check the state of the system after the record is created, verifying that it was created as expected. The test therefore needs to wait until the record is created.
I can use Mockito to create a spy for the function that creates the record. Mockito even has the option to wait for the method to be called via Mockito.timeout, giving up if a certain amount of time has elapsed without the method being called:
// Use or create/wire in spy. In my case, this is set up with #SpyBean from spring-boot-test.
RecordCreationService recordCreationServiceSpy = ...;
testClass.update(someValue);
Mockito.verify(recordCreationServiceSpy, Mockito.timeout(10_000)).createRecord(ArgumentMatchers.any());
However, this merely waits for the call to have started, not for it to have been completed. Thus, this enters a race condition where the verification can finish before the desired call completes.
How can I cleanly and simply wait for the completion of a process before verifying in JUnit with Mockito?
This functionality doesn't directly exist in Mockito, as there is currently an open issue to add this functionality to Mockito (Mockito issue #1089).
The solution I am currently using is to write a custom answer for the spied method that waits for the call to be completed before returning. I then verify the result normally afterward.
#SpyBean
private RecordCreationService recordCreationServiceSpy;
#Test(timeout = 10_000)
public void recordShouldBeCreatedWhenDataIsUpdated() {
// Set up test here
updateValueAndWait(value);
assertEquals(1, recordRepository.findAll().size());
// Perform any additional verifications
}
private void updateValueAndWait(String value) {
CountDownLatch latch = new CountDownLatch(1);
Mockito.doAnswer(invocation -> {
Object result = invocation.callRealMethod();
latch.countDown();
return result;
}).when(recordCreationServiceSpy).insertRecord(any());
testClass.update(value);
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

Breaking a local dependency to unit test a void method

I am practicing with mockito, but I am a bit stuck on how to test a method that depends on a call to method in a local object.
See the following example:
public class Worker {
public void work() {
Vodka vodka = new Vodka();
vodka.drink();
}
}
This worker, instead of doing his job, he likes drinking. But I want to add a test to prove that he drinks while he works. But there is no way of doing so, because I must verify that the method drink() is called when the method work is called. I think you agree with me, that this is impossible to test, so I need to break the dependency before starting to test.
Here is my first doubt, what do you think is the best way of breaking such dependency?
If I just change the scope of the vodka object to global, I think would not be good(I don't want to expose it to other parts of the class). I thought about creating a factory, something like this:
public class Worker {
private VodkaFactory vodkaFactory = new VodkaFactory();
public void work() {
Vodka vodka = vodkaFactory.getVodka();
vodka.drink();
}
}
I am not sure if I did break the dependency correctly, but what I want to do now, is test that the method drink() is called when work() is executed.
I tried this with no luck:
#Test
public void
does_the_worker_drink_while_working
() {
VodkaFactory vodkaFactory = mock(VodkaFactory.class);
Vodka vodka = mock(Vodka.class);
Worker worker = new Worker();
worker.work();
when(vodkaFactory.getVodka()).thenReturn(vodka);
verify(vodka,times(1)).drink();
}
I mock the factory and the when will detect that a new Vodka object is created by the factory. But then when I wan to verify that that method calls 1 time the method drink(), mockito tells me:
Wanted but not invoked:
vodka.drink();
-> at testing_void_methods_from_local_objects.WorkerSpecification.does_the_worker_drink_while_working(WorkerSpecification.java:22)
Actually, there were zero interactions with this mock.
I am not stubbing correctly or I am doing something wrong. Could you give me a hand completing this test and also clarify me what would be the best way of testing such untesteable methods?
I know mockito has a method called, doAnswer() which is used to mock a method call,do you think it can be useful in this case?
How should I use it?
UPDATE:
I am following the suggestions to get the when() called before the work() and also I am trying to allow the factory to be set from outside of the class:
#Test
public void
does_the_worker_drink_while_working
() {
VodkaFactory vodkaFactory = mock(VodkaFactory.class);
Vodka vodka = mock(Vodka.class);
Worker worker = new Worker();
when(vodkaFactory.getVodka()).thenReturn(vodka);
worker.work();
verify(vodka,times(1)).drink();
}
This is now the production code now:
public class Worker {
private VodkaFactory vodkaFactory;
public void work() {
Vodka vodka = vodkaFactory.getVodka();
vodka.drink();
}
public void setVodkaFactory(VodkaFactory vodkaFactory) {
this.vodkaFactory = vodkaFactory;
}
The exception that I get is the following:
java.lang.NullPointerException
at testing_void_methods_called_from_local_objects.Worker.work(Worker.java:9)
This is the line that says vodka.drink()
Sorry by I still confused on what is the problem.
Your worker creates his own factory class here:
private VodkaFactory vodkaFactory = new VodkaFactory();
The mock you are creating is completely detached from the worker instance and thus the lack of interaction. To make it work, factory has to be injected to worker from "the outside", say via constructor injection.
If this is legacy code, you could use reflection to replace private factory instance with mocked one.
As noted by JB Nizet in comment, your mock setup comes after work is already called. In order to make things right, inject mock and set it up before you call any code utilizing it.
You need to set your vodkaFactory:
#Test
public void
does_the_worker_drink_while_working() {
VodkaFactory vodkaFactory = mock(VodkaFactory.class);
Vodka vodka = mock(Vodka.class);
Worker worker = new Worker();
when(vodkaFactory.getVodka()).thenReturn(vodka);
//call your setter
worker.setVodkaFactory(vodkaFactory);
worker.work();
verify(vodka,times(1)).drink();
}
It is more comment than an answer. In addition to make factory an injectable dependency, you can also make sure to train your mock when(vodkaFactory.getVodka()).thenReturn(vodka); before interacting with it worker.work();
There is a logical error in the code you are trying to test. Because you have created VodkaFactory instance inside of the Worker class and moreover you have made that field private.
The best solution would be to pass a reference to VodkaFactory from outside of the class.
public class Worker {
private VodkaFactory vodkaFactory;
public void work() {
Vodka vodka = vodkaFactory.getVodka();
vodka.drink();
}
public void setVodkaFactory(VodkaFactory vf) {
vodkaFactory = vf;
}
}
Now, in your #Test you can pass your mocked VodkaFactory instance using setVodkaFactory setter.
The following is a complete JMockit unit test which exercises the Worker#work() method in isolation from the implementation of its Vodka dependency:
#Test
public void workTest(#Mocked final Vodka mockBeverage)
{
new Worker().work();
new Verifications() {{ mockBeverage.drink(); times = 1; }};
}

JUnit/Mockito test failing for bizarre reason

I have a very simple method that I am trying to unit test:
public class MyAntTask extends org.apache.tools.ant.Task {
public void execute() {
fire();
}
public void fire() {
// Do stuff
}
}
I just want to write a unit test that confirms that calling execute() always invokes fire(), so I wrote this:
#Test
public void executeCallsFire() {
//GIVEN
MyAntTask myTask = Mockito.mock(MyAntTask.class);
// Configure the mock to throw an exception if the fire() method
// is called.
Mockito.doThrow(new RuntimeException("fired")).when(myTask).fire();
// WHEN
try {
// Execute the execute() method.
myTask.execute();
// We should never get here; HOWEVER this is the fail() that's
// being executed by JUnit and causing the test to fail.
Assert.fail();
}
catch(Exception exc) {
// THEN
// The fire() method should have been called.
if(!exc.getMessage().equals("fired"))
Assert.fail();
}
}
I guess (and I'm by no means an expert) Mockito normally can't mock methods that return void, but this is a workaround. You basically say "wrap my object with a Mock that will always return a specific RuntimeException whenever a particular method is about to get executed". So, instead of fire() actually executing, Mockito just sees that its about to execute and throws an exception instead. Execution verified? Check.
Instead of passing, it fails at the first Assert.fail() just below the call to myTask.execute().
For the life of me, I can't figure out why. Here's the first 10-or-so lines of the enormous stack trace JUnit is giving me for the fail:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:92)
at org.junit.Assert.fail(Assert.java:100)
at net.myproj.ant.tasks.MyAntTaskUnitTest.executeCallsFire(MyAntTaskUnitTest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
Any thoughts here, ye Mockito Gurus of StackOverflow? Thanks in advance!
Because myTask is a mock, the real object isn't called at all. To call a real object, use a spy.
You can test that a method is called using verify so there's no need for the exceptions.
public void executeCallsFire() {
MyAntTask myTask = Mockito.spy(new MyAntTask());
myTask.execute();
Mockito.verify(myTask).fire();
}
Wanting to mock the object that you're testing doesn't seem right though. It's usually better to design the test so that you're verifying calls to a separate object instead.
I see here more design issue:
why do you need one line method and both of them are public?
the mocks are for simulating dependencies and not for the class under test
if you'll make fire (quite unclear name) as private. You shouldn't test private behavior of your class

Spring Tests : transaction not rolling back after test method executed

I'm trying to create integration tests for a legacy application deployed on Weblogic 8.1 using a subclass of AbstractTransactionalJUnit4SpringContextTests.
My test method has the following annotations :
#Test
#Rollback(true)
public void testDeployedEJBCall throws Exception {...}
My test class also references beans of type org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean, which proxy the EJBs deployed on my weblogic server.
When I call methods on this proxy bean in a sequencial manner in my test method, the transaction rolls back correctly at the end of the test.
e.g. :
#Test
#Rollback(true)
public void testDeployedEJBCall throws Exception {
Long result1 = myejb.method(100L);
Long result2 = myejb.method(200L);
...
}
However, I would like to make 2 parallel calls to the same EJB method. Therefore I've made an inner class that implements Callable, in order to call my methods in 2 different Threads and hope to run those in parallel.
However, doing this seems to make the ejb methods to be called outside my transaction, and nothing is rolled back.
Here is what the full test class would like when I run the method calls in parallel :
import org.springframework.test.annotation.*;
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
#ContextConfiguration(locations = {"classpath:path/to/tests-config.xml"})
#TransactionConfiguration(defaultRollback=true)
public final class IntegrationTests extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
protected JndiTemplate jndiTemplate;
#Resource
protected Proxy myEJB;
public IntegrationTests() {
super();
this.logger = Logger.getLogger(IntegrationTests.class);
}
#Test
#Rollback(true)
public void testDeployedEJBCall() throws Exception {
// Create a thread pool for parallel execution.
ExecutorService exec = Executors.newFixedThreadPool(2);
// Prepare the tasks for parallel execution
List<CallEJBTask> tasks = new ArrayList<CallEJBTask>();
tasks.add(new CallEJBTask(100L, this.myEJB));
tasks.add(new CallEJBTask(200L, this.myEJB));
// Execute all pending tasks in the exec Threadpool
List<Future<Long>> results = exec.invokeAll(tasks);
// Get the results of each task
Long result1 = results.get(0).get();
Long result2 = results.get(1).get();
...
}
}
private class CallEBJTask implements Callable<Long> {
private final Long valueToTest;
private final MyEJB myEJB;
public CallEJBTask(Long valueToTest, Proxy myEJBProxy)
this.valueToTest = valueToTest;
this.myEJB = (MyEJB)myEJBProxy;
}
public Long call() throws Exception {
return getResult();
}
public Long getResult() {
Long result = null;
try {
result = this.myEJB.method(this.patient);
} catch (Exception e) {
...
}
return result;
}
}
Is there a way to make this rollback ???
Thanks for your help.
Regards,
Philippe
Not automatically, no. The problem is that the two extra threads don't participate in the transaction, hence their actions don't rollback.
What is the purpose of the two parallel executions? You will unlikely be able to test for concurrency issues with this approach, if that is what you're aiming for.
Edit: The problem is that testing for concurrency issues is very hard, because your tests are, at best, probabilistic ­­­­– success or failure depend on subtle timing issues that may only surface on the billionth run. See this Serverside article for a good summary of the basics.
The rule of thumb should be to avoid hand-coding threading whenever possible, as it is hard to get right and difficult to test. If you can, avoid shared state between threads, and if there is no way around it, rely on the concurrent data structures and asynchronous executors from the java.util.concurrent package.

Categories