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)
Related
I have some service like this:
class SomeService{
private final Executor executor = Executors.newFixedThreadPool(10);
void handle(SomeEvent event) {
executor.execute(
() -> {
//... logic omitted
if (isBadCase()) {
throw new RuntimeException("Something bad happen");
}
//... time consuming logic continued
}
);
}
...
//other methods
}
And I want to test "badCase", that RuntimeException("Something bad happen") is thrown.
Is it possible to achieve using JUnit5?
For other cases "normal" or "notSoBad" I've implemented workaround which is just a wait cycle for some condition is met for corresponding case, like this:
private void awaitForNormalConditionIsMet(int seconds) {
for (int step = 1; step <= seconds * 40; step++) {
if (normalConditionIsMet()) return;
else {
try {
System.out.println("Waiting for condition - " + (step * 25) + "ms");
Thread.sleep(25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Assertions.fail();
}
And this workaround works well when I have something corresponding to check.
But for the "badCase" nothing corresponding is changed, only the exception is thrown.
And I cannot extract the exception throwing logic from executor.
Could you please help?
You might want to refactor code especially if your Runnable has more complex logic.
If you make it a separate unit to test you have more control with it. And testing is more easy, for example:
public class SomeService {
private final Executor executor = Executors.newFixedThreadPool(10);
void handle(SomeEvent event) {
executor.execute(new MyRunnable(event));
}
// This is inner non-static in my example class because isBadCase()
// could be in service. Of course this isBadCase could be anywhere.
public class MyRunnable implements Runnable {
private SomeEvent event;
public MyRunnable(SomeEvent event) {
this.event = event;
}
#Override
public void run() {
if (isBadCase()) {
throw new RuntimeException("Something bad happen");
}
}
}
public boolean isBadCase() {
return false;
}
}
Now there is no problem with threads or so because you can catch the exception in main thread directly and at the same time you are doing more granular unit testing of your code:
#ExtendWith(MockitoExtension.class)
class SomeServiceTest {
// Spy is because you want to mock normal case for isBadCase = false
// to true so causing the exception to be thrown
#Spy
private SomeService someService;
#Test
void testOk() {
someService.new MyRunnable(new SomeEvent()).run();
}
#Test
void testBadCase() {
Mockito.when(someService.isBadCase()).thenReturn(true);
MyRunnable myRunnable = someService.new MyRunnable(new SomeEvent());
assertThrows(RuntimeException.class, () -> myRunnable.run());
}
}
The use case is there is a set of methods which need to be executed based on whether the previous one has returned true or not.
For example:
class Test {
boolean method1() {...}
boolean method2() {...}
boolean method3() {...}
...
void callAll() {
if(method1()) {
if(method2() {
if(method3() {
...
}
}
} else {
error();
}
}
}
There has to be an else for all the ifs.
Is there a better way of handling this scenario?
I would just do it like this:
void callAll(){
if(method1() && method2() && method3()){
// all passed
} else {
error();
}
}
Java short-circuits the && logical operation so failure in a previous method here will prevent running the next one.
If in error() you need to know which of the methods failed, you could declare an error message field for storing the information within the class and set its value corresponding the failure:
private String errorMessage;
//...
boolean method2() {
// something went wrong
errorMessage = "Failed to do method2 stuff";
}
Are more elegant way to achieve the same would be to use the Chain of responsibility design pattern and encapsulate the boolean methods in their own handler objects. Doing this would however require more refactoring to the code you currently have and more information about your specific use case.
It's easy enough to write your own varargs method to do this:
public static void run(Supplier<Boolean>... methods) {
for (Supplier<Boolean> method : methods) {
if (!method.get()) return;
}
}
Sample usage:
run(this::method1, this::method2, this::method3);
You can use some form of Observable pattern for these kind of thins too. In most normal cases it seems a bit silly to implement it but otherwise a great way to decouple code from control structures if you have a lot of these. Note that ObservableBoolean is an Android class, but just showing the logic here:
ObservableBoolean a = new ObservableBoolean();
ObservableBoolean b = new ObservableBoolean();
public void call() {
a.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
method2();
}
});
b.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
//..you end the "chain" here
}
});
method1();
}
void method1() {
if(true) {
a.set(true);
}
else {
b.set(false);
}
}
void method2() {
if(true) {
b.set(true);
}
else {
b.set(false);
}
}
I use this technique - although some would find it odd.
boolean method1() {
System.out.println("method1");
return true;
}
boolean method2() {
System.out.println("method2");
return false;
}
boolean method3() {
System.out.println("method3");
return true;
}
void callAll() {
boolean success = method1();
success = success ? method2() : success;
success = success ? method3() : success;
if (success) {
System.out.println("Success");
} else {
System.out.println("Failed");
}
}
I could suggest you to use RX approach, with rxjava it should look like
public boolean test1() {
Log.d("TESTIT", "test1 called");
return true;
}
public boolean test2() {
Log.d("TESTIT", "test2 called");
return true;
}
public boolean test3() {
Log.d("TESTIT", "test3 called");
return false;
}
public boolean test4() {
Log.d("TESTIT", "test4 called");
return true;
}
public boolean elseMethod(boolean result) {
if (result) return true;
else {
Log.d("TESTIT", "ELSE");
}
return false;
}
public void chainedCallback() {
Observable.just(test1())
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test2()))
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test3()))
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test4()))
.filter(this::elseMethod)
.subscribe();
}
call for chainedCallback() will print
test1 called
test2 called
test3 called
ELSE
You define a class that holds an action (calling one of the methods) and with a corresponding failure handler (the else block of an if call)
public static class ActionWithFailureHandler {
private Supplier<Boolean> action;
private Runnable failureHandler;
public ActionWithFailureHandler(Supplier<Boolean> action, Runnable failureHandler) {
this.action = action;
this.failureHandler = failureHandler;
}
//Getters for the instance variables
}
You make a list of the above and call each of the actions till one of the following happens
One of the actions fails (i.,e one of the method returns false). In that case, you need to execute the failureHandler corresponding to that action.
All actions pass. In this case, execute the successHandler (the logic that you execute when all methods return true).
private static void callAll(List<ActionWithFailureHandler> actionWithFailureHandlers, Runnable successHandler) {
actionWithFailureHandlers.stream()
.filter(actionWithFailureHandler -> !actionWithFailureHandler.getAction().get())
.findFirst() //Find first failing action
.map(ActionWithFailureHandler::getFailureHandler)
.orElse(successHandler)
.run(); //You might be running either the successHandler or the failureHandler for the first failed action
}
Driver code:
public static void main(String[] args) {
Test test = new Test();
List<ActionWithFailureHandler> actionWithFailureHandlers = com.google.common.collect.ImmutableList.of(
new ActionWithFailureHandler(test::method1, () -> System.out.println("Method 1 returned false")),
new ActionWithFailureHandler(test::method2, () -> System.out.println("Method 2 returned false")),
new ActionWithFailureHandler(test::method3, () -> System.out.println("Method 3 returned false"))
);
callAll(actionWithFailureHandlers, () -> System.out.println("All returned true"));
}
Exception firstly comes to my mind, but see the link below to learn more about its performance hit.
Original answer. I would do..
public class MyException extends Exception
{
}
public void doAll()
{
try
{
method1();
method2();
method3();
}catch (MyException e)
{
error();
}
}
And let's assume that method1, method2, and method3 throws MyException when it fails.
Though it does not fit your question, it is a good pattern to use Exceptions.
public class Helper
{
public Helper(Method m)
{
this.method=m;
}
public void Do() throws MyException
{
if(method.invoke()==false)
throw new MyException ();
}
}
Using this class,
public void doAll()
{
Helper [] helpers={new Helper(this::method1), new Helper(this::method2), new Helper (this::method3)};
try
{
for(Helper helper:helpers)
{
helper.Do();
}
}catch (MyException e)
{
error();
}
}
But
according to the comment of #dilix and the link, it can be a performance-expensive strategy.
So let's use them only for their purpose.
I have written a code for retrying a failed test case in selenium web driver and java.
How should we enhance the script to hold only one record in the test case output even the same test case as been executed multiple times.
I don't want the test output report to contain any redundant result entries.
Code:
Retry Logic :
package tests;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
public class Retry implements IRetryAnalyzer {
private int retryCount = 0;
private int maxRetryCount = 2; // retry a failed test 2 additional times
#Override
public boolean retry(ITestResult result) {
if (retryCount <maxRetryCount) {
retryCount++;
return true;
}
return false;
}
}
Implementation in the class
#Test(retryAnalyzer=Retry.class)
public void example() throws CustomException
{
throw new CustomException("Example");
}
Please let me know what changes are needed.
Thanks and Regards
Sushanth.G
I had the same problem before.
We used jenkins to run CI, and need to make sure all test case results were SUCCESS (even after some times of retry) then we can deploy build.
The solution is adding TestListenerAdapter to re-write test result status to SKIP if this test will be run again.
public class MyTestListenerAdapter extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult result) {
if (result.getMethod().getRetryAnalyzer() != null) {
MyRetryAnalyzer retryAnalyzer = (MyRetryAnalyzer)result.getMethod().getRetryAnalyzer();
if(retryAnalyzer.isRetryAvailable()) {
result.setStatus(ITestResult.SKIP);
} else {
result.setStatus(ITestResult.FAILURE);
}
Reporter.setCurrentTestResult(result);
}
}
}
RetryAnalyzer needs to provide another method (isRetryAvailable() in this example) for TestListenerAdapter.
public class MyRetryAnalyzer implements IRetryAnalyzer {
private static int MAX_RETRY_COUNT = 3;
AtomicInteger count = new AtomicInteger(MAX_RETRY_COUNT);
public boolean isRetryAvailable() {
return (count.intValue() > 0);
}
#Override
public boolean retry(ITestResult result) {
boolean retry = false;
if (isRetryAvailable()) {
System.out.println("Going to retry test case: " + result.getMethod() + ", " + (MAX_RETRY_COUNT - count.intValue() + 1) + " out of " + MAX_RETRY_COUNT);
retry = true;
count.decrementAndGet();
}
return retry;
}
}
Now we can add this TestListenerAdapter to test class.
#Listeners({MyTestListenerAdapter.class})
public class AppTest {
#Test(retryAnalyzer=MyRetryAnalyzer.class)
public void testSum(){
MyClass c = new MyClass();
Assert.assertEquals(c.sum(2, 3), 5);
}
}
Please see full example here: https://github.com/haojiwu/testng-retry-example
How can I tell Eclipse RCP Job management to run at most x jobs at the same time?
EDIT:
It works by using a custom scheduling rule as described in the answer.
Its important to never pass the same rule reference to more than one job.
Here is the class I use:
public class JobMaster {
private class Listener implements IJobChangeListener {
#Override
public void aboutToRun(final IJobChangeEvent event) {
}
#Override
public void awake(final IJobChangeEvent event) {
}
#Override
public void done(final IJobChangeEvent event) {
synchronized (JobMaster.this) {
running--;
System.err.println("now running " + running);
}
}
#Override
public void running(final IJobChangeEvent event) {
synchronized (JobMaster.this) {
running++;
System.err.println("now running " + running);
}
}
#Override
public void scheduled(final IJobChangeEvent event) {
}
#Override
public void sleeping(final IJobChangeEvent event) {
}
}
private class MyRule implements ISchedulingRule {
public MyRule() {
}
#Override
public boolean contains(final ISchedulingRule rule) {
if (rule == this) {
return true;
}
return false;
}
#Override
public boolean isConflicting(final ISchedulingRule rule) {
synchronized (JobMaster.this) {
if (rule == this) {
return true;
}
if (rule instanceof MyRule) {
return running >= maxRun;
}
return false;
}
}
}
private final Listener l = new Listener();
private final int maxRun;
private volatile int running = 0;
public JobMaster(final int maxRun) {
this.maxRun = maxRun;
}
public synchronized void add(final Job j) {
j.setRule(new MyRule());
j.addJobChangeListener(l);
j.schedule();
}
}
Starting with Eclipse Mars (4.5), one can use job groups to limit the number of concurrent threads:
JobGroup jobGroup = new JobGroup("Job...", /* maxThreads*/ 10, /* seedJobsCount */ 100);
for (int ii = 0; ii < 100; ii++)
{
Job job = new Job("job name")
{
#Override
protected IStatus run(IProgressMonitor monitor)
{
// do something
return Status.OK_STATUS;
}
};
job.setJobGroup(jobGroup);
job.schedule();
}
jobGroup.join(10000, monitor);
The Job Manager does not have a way to limit the overall number of jobs.
For Jobs that you are creating you could create an ISchedulingRule rule which limited the number of your jobs that run at the same time. Call Job.setRule(rule) to set the rule on the job (do this before scheduling the job).
An example scheduling rule (from Java Debug):
class SerialPerObjectRule implements ISchedulingRule {
private Object fObject = null;
public SerialPerObjectRule(Object lock) {
fObject = lock;
}
public boolean contains(ISchedulingRule rule) {
return rule == this;
}
public boolean isConflicting(ISchedulingRule rule) {
if (rule instanceof SerialPerObjectRule) {
SerialPerObjectRule vup = (SerialPerObjectRule)rule;
return fObject == vup.fObject;
}
return false;
}
}
This stops more than one job that uses a particular object from running at a time.
Update:
The job manager checks the following conditions on a scheduling rule:
// contains method must be reflexive
Assert.isLegal(rule.contains(rule));
// contains method must return false when given an unknown rule
Assert.isLegal(!rule.contains(nullRule));
// isConflicting method must be reflexive
Assert.isLegal(rule.isConflicting(rule));
// isConflicting method must return false when given an unknown rule
Assert.isLegal(!rule.isConflicting(nullRule));
Let us say there are 3 operations ops1(), ops2() and ops3(). The client can request to execute any combination of those 3. For e.g.
perform(1): Should execute ops1()
perform(2): Should execute ops2()
perform(1, 2): Should execute ops1() and if ops1() is successful then execute ops2()
perform(1, 2, 3): Should execute ops1() and if ops1() is successful then execute ops2() and if both ops1() and ops2() are successful then execute ops3()
This can go on for n ops() though for me its just 5.
What is the simple and elegant way of implementing this? Is there a pattern for this?
How about you put your ops in a list, look the operations to perform up in that list, and let the operations throw an exception if they fail? Then the perform method can simply try and perform all methods in the desired order until it's done or an exception occurs.
So
private List<Callable> ops;
public void perform(int... opNums) {
try {
for (int i : opNums) {
ops.get(i-1).call();
}
}
catch(Exception ex) {
}
}
I see a solution somewhat like this:
public void perform(int... ops) {
for(int i : ops) {
switch(i) {
case 1:
//...
// if(taskFailed) return;
break;
case 2:
//...
// if(taskFailed) return;
break;
case 3:
//...
// if(taskFailed) return;
break;
// so on for all 5
}
}
}
It's just the general idea, not tested if the syntax is entirely correct.
the "taskFailed" thing is a pseudocode.
An approach for this would be
Define a common interface for opsX methods and the classes that implement this method.
Define an enum to know which class implementation of this common interface should be called.
Define a class that will work as an orchestrator for these calls.
An implementation of this design may be
interface CommonOps {
boolean ops();
}
class Ops1 implements CommonOps {
#Override
public boolean ops() {
//...
}
}
class Ops2 implements CommonOps {
#Override
public boolean ops() {
//...
}
}
//and on...
enum OpsOrder {
OPS1,
OPS2,
OPS3
//... and on
;
}
class Orchestrator {
public boolean executeOps(OpsOrder order) {
switch (order) {
case OPS1:
return new Ops1().ops();
case OPS2:
return new Ops2().ops();
//...
default:
throw new IllegalArgumentException("Not supported.");
}
throw new UnsupportedOperationException("This exception should never be reached.");
}
public boolean orchestrate(OpsOrder ... orders) {
for (OpsOrder order : orders) {
if (!executeOps(orders)) {
return false;
}
}
return true;
}
}
This can be even more generic by having a factory of CommonOps class implementations so Orchestrator should not know which CommonOps will be called:
final class CommonOpsFactory {
private CommonOpsFactory () { }
public static CommonOps create(OpsOrder order) {
switch (order) {
case OPS1:
return new Ops1();
case OPS2:
return new Ops2();
//...
default:
throw new IllegalArgumentException("Not supported.");
}
}
}
class Orchestrator {
public boolean executeOps(OpsOrder order) {
return CommonOpsFactory.create(order).ops();
}
public boolean orchestrate(OpsOrder ... orders) {
for (OpsOrder order : orders) {
if (!executeOps(orders)) {
return false;
}
}
return true;
}
}
I would use the command pattern in combination with the Decorator for this problem. Your commands, when many, will be wrapping/decorating each others :
public class Command{
private Command subCommand;
public Command(Command subCommand){
this.subCommand=subCommand;
}
public Command(){};
public Command addSubCommand(Command command)
{
subCommand=command;
return command;
}
//A Command class is decorating itself
//by adding a behavior over its subcommand
public void execute() throws CommandExecutionException {
executeImpl();
if(subCommand!=null) subCommand.execute();
}
protected void executeImpl() throws CommandExecutionException {
//To be overiden
}
}
public class CommandA extends Command{
private CommandAExecutor ops1Handler;
protected void executeImpl(){
ops1Handler.ops1();
}
}
//....
public class CommandN extends Command{
private CommandNExecutor opsNHandler;
protected void executeImpl(){
opsNHandler.opsN();
}
}
public class Tester{
public static void main(String[] args){
Command commandA = new CommandA(new CommandAExecutor());
Command commandB = new CommandB(new CommandBExecutor());
Command commandN = new CommandN(new CommandNExecutor());
//The order here is A, N, B
commandA.addSubCommand(commandN).addSubCommand(B);
try{
commandA.execute();
}catch(CommandExecutionException e){
//...failure
}
}
}