would like to ask for help regarding unit testing my method which sets a time delay. I was only able to cover the half of this method. Here is the method
public void setDelay() {
XMLHandler objXMLHdl = new XMLHandler();
String delay = objXMLHdl.GetXMLValue("myConfig.xml", "/config/WS/delay");
String intDelay = objXMLHdl.GetXMLValue("myConfig.xml", "/config/WS/delay_minutes");
if (delay.equals("1")) {
try {
TimeUnit.MINUTES.sleep(Integer.parseInt(intDelay));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here is the test
public class WSGlobalFunctionsTest {
WSGlobalsFunctions globalFunction = new WSGlobalsFunctions();
XMLHandler objXMLHdl = new XMLHandler();
#Test
public void testSetDelay() {
globalFunction.setDelay();
}
#Test
public void testSetDelayFailed() throws NumberFormatException, InterruptedException, JAXBException {
String delay = objXMLHdl.GetXMLValue("myConfig.xml", "/config/WS/delay");
String intDelay = objXMLHdl.GetXMLValue("myConfig.xml", "/config/WS/delay_minutes");
TimeUnit.MINUTES.sleep(Integer.parseInt(intDelay));
globalFunction.setDelay();
}
Here is the XML file
<config>
<WS>
<delay>0</delay>
<delay_minutes>2</delay_minutes>
</WS>
Any help would be greatly appreciated. T
I'd restructure your code something like this:
interface Sleeper {
void sleep(int minutes);
}
class Delay {
public Delay(XmlHandler objXMLHdl, Sleeper sleeper) {
...
}
public void doDelay() {
String delay = objXMLHdl.GetXMLValue("myConfig.xml", "/config/WS/delay");
String intDelay = objXMLHdl.GetXMLValue("myConfig.xml", "/config/WS/delay_minutes");
if (delay.equals("1")) {
sleeper.sleep(Integer.parseInt(intDelay));
}
}
}
Now you can mock XmlHandler and Sleeper and test your Delay class properly, without your test needing to actually take minutes to run.
You can have a test of normal behaviour where you check that sleep() was called with the correct number of minutes, a case where delay is "0" where you check that sleep() isn't called, and a case where you pass an non-numeric string for intDelay which should throw a NumberFormatException.
You can make your code more testable without changing the interface your clients currently use. Assuming you aren't using any dependency injection framework:
class WSGlobalFunctions {
...
private Delay delay = new Delay(new XmlHandler(), new Sleeper());
...
public void setDelay() {
delay.doDelay();
}
...
}
setDelay is now trivial so you don't need to test it.
Related
I need to collect data from a public API. I want to collect it daily or twice a day.
public class AlphavantageStockRequestDispatcher {
public static void startAlphavantageStockScraper(int timeInterval) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable getStockList =
new Runnable() {
#Override
public void run() {
List<AlphavantageStock> stocks = AlphavantageStockRequest.getStockPrices(); //Method contains requests
StockDao<AlphavantageStock> dao = new JpaAlphavantageStockDao();
for (AlphavantageStock stock : stocks) {
dao.save(stock);
}
}
};
scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);
}
}
The problem is when I start it from the same class (just added main method and invoked startAlphavantageStockScraper(1); it works fine. But when I want to test it via JUnit it's not working (test class is in symmetric package name but test subfolder):
public class AlphavantageStockRequestDispatcherTest {
#Test
public void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() {
AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1);
}
}
While debugging I found out that in unit test execution a program reaches public void run() line then skips it. So there's no error. Program ends up correctly but does nothing useful.
Any help will be appreciated.
This is how asynchronous programming works. In the AlphavantageStockRequestDispatcher class you've just submitted a task but you have to wait for it's completed. There are several ways to handle this situation. I prefer state notification using java.util.concurrent.CountDownLatch. So some refactoring is recommended in AlphavantageStockRequestDispatcher class like this:
public class AlphavantageStockRequestDispatcher {
public static void startAlphavantageStockScraper(int timeInterval, CountDownLatch latch) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable getStockList =
new Runnable() {
#Override
public void run() {
System.out.println("worker started");
try {
Thread.sleep(10_000L);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("worker finished");
Optional.ofNullable(latch).ifPresent(CountDownLatch::countDown);
}
}
};
scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);
}
}
Now it's possible to test that.
public class AlphavantageStockRequestDispatcherTest {
#Test
void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1, latch);
latch.await(20, TimeUnit.SECONDS);
System.out.println("first finished - need some assertions");
}
}
so I have the following problem, I want to make a minigame on a text channel, the problem is, I want to create some sort of timeout so that people don't create multiple "listenerAdapter" instances that will just overload the bot.
the command I use to load my game event (ListenerAdapter is as follows).
#Override
public void handle(List<String> args, GuildMessageReceivedEvent event) {
// TODO Auto-generated method stub
TextChannel channel = event.getChannel();
channel.sendMessage("please type \"joingame\" to join! ").queue();
event.getJDA().addEventListener(new MinigameEvent(channel, event.getAuthor(), event));
}
then , the code I use for loading players in, is the following:
public class MinigameEvent extends ListenerAdapter {
private final long channelId, authorId;
private final int players=3;
private ArraySet<User> users;
private String textMsg;
private Message target;
private GuildMessageReceivedEvent outTimerEvent;
private boolean cancelEvent;
public MinigameEvent(MessageChannel channel, User author, GuildMessageReceivedEvent outTimerEvent) {
this.channelId = channel.getIdLong();
this.authorId = author.getIdLong();
this.outTimerEvent=outTimerEvent;
cancelEvent=false;
this.timeOut(channel);
users=new ArraySet<User>();
users.add(author);
textMsg=("registered users: "+author.getName());
channel.sendMessage(textMsg).queue((new Consumer<Message>()
{
#Override
public void accept(Message t)
{
target = t;
}
}));
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
if(event.getAuthor().isBot()) {
return;
}
//not respond on other channels
if (event.getChannel().getIdLong() != channelId) {
return;
}
MessageChannel channel = event.getChannel();
String content = event.getMessage().getContentRaw();
if(content.equalsIgnoreCase("joingame")) {
users.add(event.getAuthor());
textMsg=textMsg+", "+event.getAuthor().getName();
target.editMessage(textMsg).queue();
if(users.size()==players) {
event.getChannel().sendMessage("starting").queue();
event.getJDA().removeEventListener(this);
}
}
if(content.equalsIgnoreCase("cancel") && event.getAuthor().getIdLong()==authorId) {
cancelEvent=true;
event.getJDA().removeEventListener(this);
event.getChannel().sendMessage("this game has been canceled").queue();
}
}
private void timeOut(MessageChannel channel) {
Timer timer = new Timer();
TimerTask cooldown = new TimerTask() {
#Override
public void run() {
if(cancelEvent) {
return;
}
if(users.size()<players) {
outTimerEvent.getJDA().removeEventListener(this);
try {
destroyEvent();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
channel.sendMessage("not enough players, the game has been cancelled").queue();
}else {
return;
}
}
};
timer.schedule(cooldown, 10000L);
}
private void destroyEvent() throws Throwable {
this.finalize();
}
}
when I get to 3 people, the Listener adapter stops working as intended, also when the author of the event (the one who used the !minigame command) types cancel. but when the timer goes off, it sends the message indicating the game has been cancelled, but the listener adapter is still running, if someone tries to join after, it will allow him to do so.
I currently solved the issue by using the finalize method, but I thought that you could just do something like event.getJDA().removeEventListener(this);
Your problem is that your this refers to the nearest class declaration. In this case this is the anonymous class created by your new TimeTask() { .... To refer to the outer class which actually is registered as the listener you have to use MinigameEvent.this instead.
Read More
I would highly recommend using a lambda expression instead which doesn't have this problem. Another thing to note is your use of timer which will result in thread leaks because they are never shutdown by your code (How to cleanup a timer). Even better would be to use a single ScheduledExecutorService which you should re-use to schedule everything you need rather than creating a new one for every task. This can then be shutdown once your process ends (like the onShutdown event in JDA which is fired when shutdown() is called).
Awaitility is a great tool to unit-test concurrent production code.
Question: Is there a tool to ease writing concurrent test code?
Suppose I wanted to test java.util.concurrent.LinkedBlockingQueue.
public class BlockingQueueTest {
private LinkedBlockingQueue<String> out;
#Before
public void setUp() {
out = new LinkedBlockingQueue<>();
}
#Test
public void putThenGet() throws InterruptedException {
// that's easy because it can be done in one thread
out.put("Hello");
String taken = out.take();
assertThat(taken).isEqualTo("Hello");
}
#Test
public void getBeforePut() throws InterruptedException {
// that's more tricky because it can't be done with one thread
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(() -> {
Thread.sleep(100);
out.put("Hello");
return null;
});
executorService.shutdown();
String taken = out.take();
assertThat(taken).isEqualTo("Hello");
}
}
getBeforePut() is no fun to code. Is there a way to make it less hard and more readable, like so?
#Test
public void getBeforePut2() throws InterruptedException {
// Wanted: DSL for concurrent test-code
Concurrently.sleep(100, TimeUnit.MILLISECONDS).andThen(() -> out.put("Hello"));
String taken = out.take();
assertThat(taken).isEqualTo("Hello");
}
Using TestNG is the easiest way as for me:
#Test(threadPoolSize = 10, invocationCount = 15, timeOut = 1000)
public void testPut(){
out.put("Hello");
}
This test will run 15 times in 10 threads and should take no longer than 1000 ms.
Also you can create tests which depends on other test
#Test(dependsOnMethods = "testPut")
public void testGetAfterPut{
String taken = out.take();
assertThat(taken).isEqualTo("Hello");
}
(A) you can just use Thread without the need of an ExecutorService
#Test
public void getBeforePutWithThread() throws InterruptedException {
new Thread(() -> {
Thread.sleep(100);
out.put("Hello");
}).run();
String taken = out.take();
assertThat(taken).isEqualTo("Hello");
}
(B) You can take this all functionality to a simple function and avoid dependency on external lib
private void runWithDelay(long delay, Runnable action) {
new Thread(() -> {
try {
Thread.sleep(delay);
action.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).run();
}
#Test
public void getBeforePutWithFunction() {
runWithDelay(100, () -> out.put("Hello"));
String taken = out.take();
assertThat(taken).isEqualTo("Hello");
}
By now I'm writing all my tests in kotlin. And with kotlin testing this is easy peasy and fun!
Worth mentioning when testing with threads is JUnit's #Timeout Annotation, which prevents false tests from running infinitely.
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Timeout
import java.util.concurrent.LinkedBlockingQueue
import kotlin.concurrent.thread
class BlockingQueueKotlinTests {
// objectUnderTest
private val out = LinkedBlockingQueue<String>()
#Test
fun `put then get`() {
// that's easy because it can be done in one thread
out.put("Hello")
val taken = out.take()
assertThat(taken).isEqualTo("Hello")
}
#Test
#Timeout(1)
fun `get before put`() {
// thanks to kotlin it's really easy to do that in another thread
thread {
Thread.sleep(100)
out.put("kotlin is great!")
}
val taken = out.take()
assertThat(taken).isEqualTo("kotlin is great!")
}
}
I have a test of communication over a TCP socket where I expect the server to not respond within a set time frame when I send a certain message.
The servers behaviour is nothing I can control.
I know how to fail a test if it has not completed within a set time frame. But how can I do the opposite, make it pass for not completing within the timeframe?
I can use #Test (timeout=1000) to make a test fail if not complete within a second.
But, using Junit 4, is there a function to test for an expected timeout as a positive result? I.e. The test will fail if completed within the time frame and pass if not?
Good question. Actually you can do this using only junit tools. My idea is to inverse Timeout rule behaviour + use expected attribute of Test annotation. The only one limitation: you have to place your test in separate class, because Rule applies to all tests inside it:
public class Q37355035 {
private static final int MIN_TIMEOUT = 100;
#Rule
public Timeout timeout = new Timeout(MIN_TIMEOUT) {
public Statement apply(Statement base, Description description) {
return new FailOnTimeout(base, MIN_TIMEOUT) {
#Override
public void evaluate() throws Throwable {
try {
super.evaluate();
throw new TimeoutException();
} catch (Exception e) {}
}
};
}
};
#Test(expected = TimeoutException.class)
public void givesTimeout() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
}
}
I'm building upon the great answer by Andremoniy, don't forget to upvote his answer if you like this one!
I used the following modification to skip a test if it doesn't finish in the expected time frame. The benefit of this is that the test will be marked as Skipped by JUnit instead of Successful. This is good for optimistic execution of tests which can sometimes hang or not finish fast enough, but you don't want to mark them as failed or delete them.
public class OptimisticTestClass {
private static final int TEST_METHOD_TIMEOUT_MS = 100;
#Rule
public Timeout timeout = new Timeout(TEST_METHOD_TIMEOUT_MS, TimeUnit.MILLISECONDS) {
public Statement apply(Statement base, Description description) {
return new FailOnTimeout(base, TEST_METHOD_TIMEOUT_MS) {
#Override
public void evaluate() throws Throwable {
try {
super.evaluate();
} catch (TestTimedOutException e) {
Assume.assumeNoException("Test did not finish in the allocated time, skipping!", e);
}
}
};
}
};
// The test times out and is skipped
public void givesTimeout() throws InterruptedException {
Thread.sleep(1000);
}
}
It's simpler in Java 9
CompletableFuture.supplyAsync(() -> dormammu.bargain())
.orTimeout(1, TimeUnit.SECONDS)
.handle((result, throwable) -> {
if (!(throwable instanceof TimeoutException)) {
Assertions.fail();
}
return result;
}).get();
If the method doesn't return within 1 second, it will time out. In handle method you can make sure TimeoutException was thrown, otherwise fail the test.
I'm new to Mockito and JUnit and try to understand basic unit testing with these frameworks. Most concepts in JUnit and Mockito seem straightforward and understandable. However, I got stuck with timeout in Mockito. Does timeout in Mockito play the same role as it does in JUnit? Bellow is my code.
#Mock Timeoutable timeoutable;
#Test(timeout = 100)
public void testJUnitTimeout() {
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
}
}
#Test
public void testMockitoTimeout(){
doAnswer(new Answer() {
#Override public Object answer(InvocationOnMock invocation){
try {
Thread.sleep(1000);
} catch (InterruptedException ie){
}
return null;
}
}).when(timeoutable).longOperation();
timeoutable.longOperation();
verify(timeoutable, timeout(100)).longOperation();
}
I expected that both tests failed. But only testJUnitTimeout() failed. Why does the second test pass?
Thank you very much.
Verification with timeout is intended to be used to verify whether or not the operation has been invoked concurrently within the specified timeout.
It provides a limited form of verification for concurrent operations.
The following examples demonstrate the behaviour:
private final Runnable asyncOperation = new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
timeoutable.longOperation();
} catch (InterruptedException e) {
}
}
};
#Test
public void testMockitoConcurrentTimeoutSucceeds(){
new Thread(asyncOperation).start();
verify(timeoutable, timeout(2000)).longOperation();
}
#Test
public void testMockitoConcurrentTimeoutFails(){
new Thread(asyncOperation).start();
verify(timeoutable, timeout(100)).longOperation();
}