I would like to say Thanks to each one of you to share your knowledge and time with all of us. Here, I'm curious to know how can we write junit test case for a business logic written within CompletableFuture.runAsync()
e.g.
public class Loan{
public Transaction writeIntoCassandra(Transaction transaction){
private startTime = System.currentTimeMillis();
CompletableFuture.runAsync(()-> {
try{
writeIntoCassandraTable(transaction);
}
catch(JsonConversionException e){
}
});
CompletableFuture.runAsync(()-> {
try{
writeIntoCassandraTable2(transaction);
}
catch(JsonConversionException e){
}
});
return transaction;
}
}
I'm writing below junit test case for above implementation
#InjectMocks
private Loan loan;
public void writeIntoCassendraTest(){
String jsonTransaction = "";
ObjectMapper objectMapper = new ObjectMapper();
Transaction transaction = objectMapper.readValue(jsonTransaction, Transaction.class);
loan.writeIntoCassendra(transaction);
//assertThat();
}
Here, when I am running junits it is not executing code written after "CompletableFuture.runAsync(()-> {" that is private methods writeIntoCassandraTable(transaction) and writeIntoCassandraTable2(transaction) are not getting executed. I kept breakpoint withing try block but control is not stopping at this point.
Which is resulting low code coverage. Help me to understand why it is not getting executed and how it can be fixed. Let me know if you need more clarity or details.
I would suggest switching out runAsync with supplyAsync in your original method. Then, return something from the supplyAsync method. As for what to return, you may need to use Mockito or some other equivalent mocking library. If not that, maybe there is some dummy values/objects you could use instead? From there, just make your assertions, and you should have a working unit test.
Related
I am getting following exception while running the tests. I am using Mockito for mocking. The hints mentioned by Mockito library are not helping.
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
Here is my method:
From ps.setString I am unable to do code coverage. Can anyone help me?
public class Dao{
public int[][] batchInsertAll(Collection<UploadRequest> request, int batchSize, final String jobId) {
int[][] updateAllCounts = jdbcTemplate.batchUpdate("insert into tb_import(id,name) values("","")", request, batchSize,
new ParameterizedPreparedStatementSetter<UploadRequest>() {
public void setValues(PreparedStatement ps, UploadRequest argument) throws SQLException {
ps.setString(1, Id);
ps.setString(2, argument.getName());
}}); return updateAllCounts
}
}
Here is my test code:
#Test
public void batchInsertAll() {
int batchSize = 1000;
String jobId = "xyz";
List<UploadRequest> fileData = new ArrayList<UploadRequest>();
UploadRequest rowdata1 = new UploadRequest("1", "xyz");
UploadRequest rowdata1 = new UploadRequest("1", "abc");
fileData.add(rowdata1);
fileData.add(rowdata2);
int[][] updateAllCounts = new int[][] { { 1, 2 }, { 3, 4 } };
try {
Mockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
PreparedStatement ps = Mockito.mock(PreparedStatement.class);
ParameterizedPreparedStatementSetter bpss = invocation.getArgumentAt(1,
ParameterizedPreparedStatementSetter.class);
try {
bpss.setValues(ps, 1);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return updateAllCounts;
}
}).when(jdbcTemplate).batchUpdate(anyString(), fileData, 1000,
any(ParameterizedPreparedStatementSetter.class));
} catch (Exception e) {
assert (true);
}
mockDao.batchInsertAll(fileData, 1000, jobId);
}
First you have to think - what is your goal here?
You wrote a class Dao and a method batchInsertAll. I would think you'd want to test that. If you want to test that though you need to actually call that method. Calling
mockDao.batchInsertAll(fileData, 1000, jobId);
makes it look, like you're just calling a mock you created to test it, which obviously will do nothing except do whatever you configured that mock to do.
Also, the catching of Exception with assert(true) will not do what you think it'll do - this is a base Java assertion used for sanity checks in non-production builds. It will either not be run at all (as might be default behaviour when running an application without appropriate flag to enable them) or do nothing (since true is true, so it passes). It will not end the test with a positive result, it will not tell you it happened, it doesn't even count as test assertion. You might want to add some logging there, as without knowing an exception you didn't expect was thrown any number of shenanigans can slip by. Or even better, don't catch exceptions in tests. If unexpected exceptions get thrown you want the test to fail anyway right?
As to your direct problem it's hard to tell for sure without seeing the entire test class (I can see three mocks in your code - jdbcTemplate, mockDao and ps, only one of which is initialized as a Mock in the code you've given us, you only stub jdbcTemplate and from what I can tell without running the code it looks correct). Either the problem is somewhere you haven't shown us, or exception is thrown during stubbing of jdbcTemplate, causing that to not finish and fail leaving mock in invalid state.
Also worth noting, most of your code in doAnswer method is irrelevant. Even if you call real batchInsertAll that in turn will call jdbcTemplate.batchUpdate with some parameters, and your mock will return updateAllCounts array. doAnswer() line of methods is useful only if you need to change what your mock returns based on input arguments, otherwise you do some useless calculations you could have done wrong and end up with same result as .thenReturn(updateAllCounts) would.
I am having thoughts on how do I write a test case for this using mockito.
Example, part of my logic in my main thread is to create a thread that does 3 things.
Please see my annotated code below.
Now the RequestThread can be spawn many times depending on the number of inputs coming from the main program.
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread implements Runnable{
private final String request;
public RequestThread(String request) {
this.request = request;
}
#Override
public void run() {
//1. Instantiate a service passing the required request parameter
MyDataWebService service = new MyDataWebService(request);
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("/someDir/" + request);
Files.write(file, dataList, Charset.forName("UTF-8"));
}
}
}
My issue is this, I could not figure out how to properly write a JUnit/Mockito test for a threaded class.
I am not that well verse on Mockito and JUnit in general so I am looking for a way to unit test
a threaded application.
Can somebody guide me on how can I unit test such thing?
You need to bring some changes to your code in order to make it more testing-friendly. In particular:
Objects that you want to mock should implement an interface
Do not instantiate objects to mock in the function that you want to test
Here is a rewrite of the classes so that you can mock MyDataWebService and test RequestThread. Based on this example you will more easily be able to write a full test for the MainThreads class.
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread extends Thread {
private final String request;
// One important thing to note here, "service" has to be non-final. Else mockito won't be able to inject the mock.
private MyDataWebServiceInterface service;
public RequestThread(String request) {
this.request = request;
//1. Instantiate a service passing the required request parameter
// => do it in constructor, or passed as parameter, but NOT in the function to test
service = new MyDataWebService(request);
}
#Override
public void run() {
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("someDir/" + request);
try {
Files.write(file, dataList, Charset.forName("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The interface & implementation for MyDataWebService:
interface MyDataWebServiceInterface {
List<String> requestData();
}
class MyDataWebService implements MyDataWebServiceInterface {
public MyDataWebService(String request) {
}
#Override
public List<String> requestData() {
return Arrays.asList("foo", "bar");
}
}
And a test using mockito. Note, the checks for existing file and thread sleeping may not be the most elegant thing to do here. If you can afford adding some marker in RequestThread to indicate that the data has been written, it would certainly make the test better and safer (filesystems i/o are sometimes tricky to test).
#RunWith(MockitoJUnitRunner.class)
public class RequestThreadTest {
private static final Path FILE = Paths.get("someDir", "sample");
#Mock
MyDataWebServiceInterface service;
#InjectMocks
MainThreads.RequestThread reqThread = new MainThreads.RequestThread("sample");
#Before
public void setup() throws IOException, InterruptedException {
if (Files.exists(FILE)) {
Files.delete(FILE);
while (Files.exists(FILE)) {
Thread.sleep(50);
}
}
}
#Test
public void shouldWriteFile() throws InterruptedException {
Mockito.when(service.requestData()).thenReturn(Arrays.asList("one", "two"));
reqThread.start();
while (!Files.exists(FILE)) {
Thread.sleep(50);
}
// HERE run assertions about file content
}
}
Now, testing asynchronous code is often more complicated than synchronous because you will often face non-determinist behaviours, timing issues, etc. You may want to set a timeout on your test, but remember: continuous integration tools (jenkins, travis etc.) will often run slower than your machine, it's a common cause of problems, so don't set it too tight. As far as I know there is no "one-fits-all" solution for non-determinist issues.
There's an excellent article about non-determinism in tests by Martin Fowler: https://martinfowler.com/articles/nonDeterminism.html
A distinctive non-answer: in 2018, you don't use "raw" threads any more.
Java has much better abstractions to offer by now, for example the ExecutorService. And guess what: when you have your code submit tasks into such a service, you can probably test it using a same-thread executor service.
Meaning: by using such abstractions and dissecting your delivery into specific services, you might be able to (almost) fully test not only the small units, but also how tasks come into your system and worked on.
In other words: you unit test your "tasks", then you "unit" test the integration of tasks when they go into such an executor. Then you are only left with a bit of real function/integration testing to check that the "true parallel" solution behaves as expected.
Anything else gets complicated quickly. Using real threads in ordinary unit tests can lead to inconsistent behavior, or increased runtimes (like the test waiting for threads to asynchronously doing something).
As in your example: your test would simply sit there and regularly check if the expected file was written with the expected content. Leading to: how long should it wait before failing? Waiting not long enough means that your test will occasionally fail because code sometimes just takes longer. If you wait too long, that adds up to the overall time you need to run your tests. You don't want to end up with hundreds of unit tests were some need 10, 20 seconds because "waiting for other threads".
Today I had to write a method which get a String as a parameter, make a new thread and write it out to the consol after 5 seconds waiting, so something like this:
public void exampleMethod(final String str){
Runnable myRunnable = new Runnable(){
public void run(){
try {
Thread.sleep(5000);
System.out.println(str);
} catch (InterruptedException e) {
//handling of the exception
}
}
};
Thread thread = new Thread(myRunnable);
thread.start();
//some other things to do
}
My question is: How can I test and what should I test in here with JUnit?
Thank you!
There is nothing complex in this method. You are only using standard API-methods: Thread.sleep, System.out.println, ...
The parameter is just printed, you don't modify it nor use it for a calculation or another method.
There are no side-effects to your own written code, just to the STL.
And there is no result of the method, which you could test.
In my opinion it is not necessary and not simply possible to test it.
The only thing you could test (and even that wouldn't be trivial), is, if after an amount of time the String is printed.
[...] JUnit finishes execution while the thread is still alive. There could have been problems down the line, toward the end of that thread's execution, but your test would never reflect it.
The problem lies in JUnit's TestRunner. It isn't designed to look for Runnable instances and wait around to report on their activities. It fires them off and forgets about them. For this reason, multithreaded unit tests in JUnit have been nearly impossible to write and maintain.
Well, the source - this article - is from 2003 and there's no guarantee that this hasn't been fixed yet, but you may try it out yourself.
My suggestion would be:
Run your code and measure the time it takes. Then add some 1000 milliseconds and but a Thread.sleep(executionTime+1000); after you started you asynchronous task. Not that elegant, but should work in practice. If you want more elegance here (and waste less time), you may want to look for framework that provide a solution.
...Or if you start your Thread directly in the test, you may also use Thread.join to wait, but you will have cases, where you aren't able to do that.
EDIT:
Also check this article, which could provide a solution to pipe those errors to the main thread:
public class AsynchTester{
private Thread thread;
private volatile Error error;
private volatile RuntimeException runtimeExc;
public AsynchTester(final Runnable runnable) {
thread = new Thread(new Runnable() {
#Override
public void run() {
try {
runnable.run();
} catch (Error e) {
error = e;
} catch (RuntimeException e) {
runtimeExc = e;
}
}
});
}
public void start() {
thread.start();
}
public void test() throws InterruptedException {
thread.join();
if (error != null)
throw error;
if (runtimeExc != null)
throw runtimeExc;
}
}
Use it like that:
#Test
public void test() throws InterruptedException {
AsynchTester tester = new AsynchTester(new Runnable() {
#Override
public void run() {
//async code
}
});
tester.start();
tester.test();
}
The issue here is that you are trying to test an interaction instead of a simple returned result or a state change. However, that does not mean it can't be done.
The standard out PrintStream can be replaced with System.setOut(). You can inject your own mock implementation that would allow you verify that the String was written to the stream. You just have to be careful, since this changes the global state, it might effect other code or tests that rely on standard output. At a minimum, you will have to put back the original stream. But things might get more complicated if tests are running in parallel.
This takes us to the next issue, the sleep. There isn't a strong guarantee to how long a sleep will block. This means your test would have to provide some buffer to ensure that the thread had time to write the String before checking the state of the mock stream. You don't want your test to be flaky because of some execution timing jitter. So you would have to decide what buffer you would consider acceptable.
An alternative approach would be to change the implementation of the code so that it is easier to test.
The simplest way to do this is to remove all the static dependencies. Instead of explicitly referencing System.out, the class could be initialized with with an PrintStream to write to. Additionally, you could define an interface that would wrap Thread.sleep(). For testing purposes, you can initialize the class with the mock stream and no-op implementation of the sleep interface. However, you may still have some timing issues as you need the newly created thread to execute before continuing the test.
The other thing you can do is take a step back and decide how much you care about this code being tested. There are only 4 interesting lines of code in this sample and none of them are complicated. Having a code review could be sufficient to ensure there are no bugs.
However, if the business logic is more complicate than writing to standard out, you might decided that testing that is important. The good news is that scheduling a task in an executor is straight forward and that is the part that is making the testing hard. You could make an abstraction that encompasses the scheduling of the task in a background thread. Then provide yourself with more direct access to the business logic in order to test that.
I have often solved that, by providing a ResultTarget which implements an interface IResultTarget to the thread,
In productive code the result will be a list that contains the calculation result. (or null)
In your unit test the ResultTarget is the unit test class itself, which then easily can check the received result.
public Interface IResultTarget {
List getResult();
}
public void ThreadTest extends TestCase implements IResultTarget {
List result;
public List getResult(
return this.result;
}
public void testThread() {
MyRunnable myRunnable= new MyRunnable ();
myRunnable.setResultTarget(this);
Thread thread = new Thread(myRunnable);
thread .start();
Thread.sleep(5 * 1000);
// expecting one element as result of the work of myRunnable.
assertEquals(1, result.size());
}
}
I'm looking for a way to verify with Mockito, that there wasn't any interaction with a given mock during a test. It's easy to achieve that for a given method with verification mode never(), but I haven't found a solution for the complete mock yet.
What I actually want to achieve: verify in tests, that nothing get's printed to the console. The general idea with jUnit goes like that:
private PrintStream systemOut;
#Before
public void setUp() {
// spy on System.out
systemOut = spy(System.out);
}
#After
public void tearDown() {
verify(systemOut, never()); // <-- that doesn't work, just shows the intention
}
A PrintStream has tons of methods and I really don't want to verify each and every one with separate verify - and the same for System.err...
So I hope, if there's an easy solution, that I can, given that I have a good test coverage, force the software engineers (and myself) to remove their (my) debug code like System.out.println("Breakpoint#1"); or e.printStacktrace(); prior to committing changes.
Use this :
import static org.mockito.Mockito.verifyZeroInteractions;
// ...
private PrintStream backup = System.out;
#Before
public void setUp() {
System.setOut(mock(PrintStream.class));
}
#After
public void tearDown() {
verifyZeroInteractions(System.out);
System.setOut(backup);
}
verifyZeroInteractions(systemOut);
As noted in comments, this doesn't work with a spy.
For a roughly equivalent but more complete answer, see the answer by gontard to this question.
Since the original correct answer, verifyZeroInteractions has been deprecated, use verifyNoInteractions instead:
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
public class SOExample {
#Test
public void test() {
Object mock = mock(Object.class);
verifyNoInteractions(mock);
}
}
You could try a slightly different tack:
private PrintStream stdout;
#Before public void before() {
stdout = System.out;
OutputStream out = new OutputStream() {
#Override public void write(int arg0) throws IOException {
throw new RuntimeException("Not allowed");
}
};
System.setOut(new PrintStream(out));
}
#After public void after() {
System.setOut(stdout);
}
If you preferred, you could switch the anonymous type for a mock and verify as Don Roby suggests.
One way of solving this problem is to refactor the class that you're testing, to allow for the injection of a PrintStream that can be used for output. This will let you unit test it, without relying on the behaviour of the System class. You could use a package-private constructor for this injection, since you'll only ever use it from the corresponding test class. So it might look something like this.
public class MyClass{
private PrintWriter systemOut;
public MyClass(){
this(System.out);
}
MyClass(PrintWriter systemOut){
this.systemOut = systemOut;
// ...any other initialisation processing that you need to do
}
}
and within the class itself, use the systemOut variable instead of System.out wherever you call the latter.
Now, within the test class, make a mock PrintStream, and pass it to the package-private constructor, to get the object that you're going to test. Now you can run any actions you like from your tests, and use verify to check their effects on your mock PrintStream.
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.