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".
Related
I want to do Unit Tests for asynchronous methods in android. The result needs to be a "notified by observer's callback". Have a look at the below example. How can I write a unit test case for doSomething() method?
public interface IFooObserver {
void onResult(String result);
}
public class Foo {
private IFooObserver mObserver;
public Foo(IFooObserver observer) {
mObserver = observer;
}
public void doSomething() {
new Thread(new Runnable() {
#Override
public void run() {
// do something..
mObserver.onResult("hello, world!");
}
}).start();
}
}
Simply: don't use "bare metal" threads.
Use ExecutorServices instead - because that allows you to use dependency injection to turn your multi-threaded code into a single-threaded thing for testing - using a Same Thread Executor Service.
Example:
class Whatever {
private final ExecutorService service;
Whatever() { this ( Executors.newSingleThreadExecutor() ); }
Whatever(ExecutorService service) { this.service = service; }
void foo() {
service.submit ( ... whatever
The point is: when you are using a thread directly, you have no control whatsoever there. Most likely, that will lead to test cases that need complicated signaling, or worse: rely on calling sleep() here or there. And that is always bad - it increases the execution time of your tests; or, worse, you get the timing wrong; and occasionally your tests fail during regression. Because of different load on your test system; and threads showing different runtime characteristics.
So, long story short: if possible, avoid using threads directly; instead use the aforementioned concept to simply avoid multiple threads for testing.
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 currently unit testing my asynchronous methods using thread locking, usually I inject a CountDownLatch into my asynchronous component and let the main thread wait for it to reach 0. However, this approach just looks plain ugly, and it doesn't scale well, consider what happens when I write 100+ tests for a component and they all sequentially have to wait for a worker thread to do some fake asynchronous job.
So is there another approach? Consider the following example for a simple search mechanism:
Searcher.java
public class Searcher {
private SearcherListener listener;
public void search(String input) {
// Dispatch request to queue and notify listener when finished
}
}
SearcherListener.java
public interface SearcherListener {
public void searchFinished(String[] results);
}
How would you unit test the search method without using multiple threads and blocking one to wait for another? I've drawn inspiration from How to use Junit to test asynchronous processes but the top answer provides no concrete solution to how this would work.
Another approach:
Just dont start the thread. thats all.
Asume you have a SearcherService which uses your Searcher class.
Then don't start the async SearcherService, instead just call searcher.search(), which blocks until search is finished.
Searcher s = new Searcher();
s.search(); // blocks and returns when finished
// now somehow check the result
Writing unit test for async never looks nice.
It's necessary that the testMyAsyncMethod() (main thread) blocks until you are ready to check the correct behaviour. This is necessary because the test case terminates at the end of the method. So there is no way around, the question is only how you block.
A straightforward approach that does not influence much the productive code is to
use a while loop: asume AsyncManager is the class under test:
ArrayList resultTarget = new ArrayList();
AsyncManager fixture = new AsyncManager(resultTarget);
fixture.startWork();
// now wait for result, and avoid endless waiting
int numIter = 10;
// correct testcase expects two events in resultTarget
int expected = 2;
while (numIter > 0 && resulTarget.size() < expected) {
Thread.sleep(100);
numIter--;
}
assertEquals(expected, resulTarget.size());
productive code would use apropriate target in the constructor of AsyncManager or uses another constructor. For test purpose we can pass our test target.
You will write this only for inherent async tasks like your own message queue.
for other code, only unitest the core part of the class that performs the calculation task, (a special algorithm, etc) you dont need to let it run in a thread.
However for your search listener the shown principle with loop and wait is appropriate.
public class SearchTest extends UnitTest implements SearchListener {
public void searchFinished() {
this.isSearchFinished = true;
}
public void testSearch1() {
// Todo setup your search listener, and register this class to receive
Searcher searcher = new Searcher();
searcher.setListener(this);
// Todo setup thread
searcherThread.search();
asserTrue(checkSearchResult("myExpectedResult1"));
}
private boolean checkSearchResult(String expected) {
boolean isOk = false;
int numIter = 10;
while (numIter > 0 && !this.isSearchFinished) {
Thread.sleep(100);
numIter--;
}
// todo somehow check that search was correct
isOk = .....
return isOk;
}
}
Create a synchronous version of the class that listens for its own results and uses an internal latch that search() waits on and searchFinished() clears. Like this:
public static class SynchronousSearcher implements SearcherListener {
private CountDownLatch latch = new CountDownLatch(1);
private String[] results;
private class WaitingSearcher extends Searcher {
#Override
public void search(String input) {
super.search(input);
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public String[] search(String input) {
WaitingSearcher searcher = new WaitingSearcher();
searcher.listener = this;
searcher.search(input);
return results;
}
#Override
public void searchFinished(String[] results) {
this.results = results;
latch.countDown();
}
}
Then to use it, simply:
String[] results = new SynchronousSearcher().search("foo");
There are no threads, no wait loops and the method returns in the minimal possible time. It also doesn't matter if the search returns instantly - before the call to await() - because await() will immediately return if the latch is already at zero.
I have a bunch of integration tests that need to have a database populated before running. This task takes about 30 minutes, so it is not feasible to run it before every test.
I'm using junit and I'd like to be able to annotate this one class with something so that it runs and completes before the others start. Is this possible?
(most of the annotations I found only work on methods, e.g. #Rule)
I've done this in the past by adding setup and teardown functions to the individual test classes, annotated with #BeforeClass and #AfterClass.
#BeforeClass
public static void setupBeforeClass() {
DatabasePopulater.populate();
}
#AfterClass
public static void tearDownAfterClass() {
DatabasePopulater.dePopulate();
}
If more than one test class requires the same setup to be done, the setup function can do a kind of reference counting to make sure they only do their work the first time it's called:
public class DatabasePopulater {
AtomicInteger invocations = new AtomicInteger();
....
public static void populate() {
if (0 == ivocations.getAndIncrement()) {
// Actually populate DB
}
}
public static void dePopulate() {
if (0 == ivocations.decrementAndGet()) {
// Actually clear DB
}
}
If you are using something like ant/gradle to execute the test suite, you could separate out the db population into a standalone java program and then have a depends="populateDB" on the junit task.
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.