This question already has answers here:
Interrupt test class at the first test failure
(3 answers)
Closed 1 year ago.
I have to write a test divided into several steps. Each step is based on the previous one so if one fails, testing should be stopped.
#TestMethodOrder(AlphanumericOrder.class)
public class TestCase {
#Test
public void step10() {
Assertions.assertTrue(true);
}
#Test
public void step20() {
Assertions.assertTrue(false);
}
#Test
public void step30() {
Assertions.assertTrue(true);
}
#Test
public void step40() {
Assertions.assertTrue(true);
}
}
In the example above testing should be terminated after step20(). I implemented custom MethodOrder to ensure correct sequence of execution. The problem I have is how to stop other tests after one fails? I tried to implement TestWatcher with no success. Is there any built-in mechanism in JUnit5 that can solve my problem?
Working solution that was shared in the comments:
Reference: Interrupt test class at the first test failure
#ExtendWith(StepwiseExtension.class)
#TestMethodOrder(AlphanumericOrder.class)
public class TestCase {
#Test
public void step10() {
Assertions.assertTrue(true);
}
#Test
public void step20() {
Assertions.assertTrue(false);
}
#Test
public void step30() {
Assertions.assertTrue(true);
}
#Test
public void step40() {
Assertions.assertTrue(true);
}
#BeforeEach
public void before(){
}
}
class StepwiseExtension implements ExecutionCondition, TestExecutionExceptionHandler {
#Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext extensionContext) {
ExtensionContext.Namespace namespace = namespaceFor(extensionContext);
ExtensionContext.Store store = storeFor(extensionContext, namespace);
String value = store.get(StepwiseExtension.class, String.class);
return value == null ? ConditionEvaluationResult.enabled("No test failures in stepwise tests") :
ConditionEvaluationResult.disabled(String.format("Stepwise test disabled due to previous failure in '%s'", value));
}
#Override
public void handleTestExecutionException(ExtensionContext extensionContext, Throwable throwable) throws Throwable {
ExtensionContext.Namespace namespace = namespaceFor(extensionContext);
ExtensionContext.Store store = storeFor(extensionContext, namespace);
store.put(StepwiseExtension.class, extensionContext.getDisplayName());
throw throwable;
}
private ExtensionContext.Namespace namespaceFor(ExtensionContext extensionContext){
return ExtensionContext.Namespace.create(StepwiseExtension.class, extensionContext.getParent());
}
private ExtensionContext.Store storeFor(ExtensionContext extensionContext, ExtensionContext.Namespace namespace){
return extensionContext.getParent().get().getStore(namespace);
}
}
Related
I have a test scenario where I need to mock a Consumer parameter.
In the following code the startTracer is the method to be tested.
class TracerService {
private TracerController tracerController;
public void startTracer(String tracerName, Object param1) {
if (attendStartConditions(tracerName, param1)) {
executeOnTracerControllerScope(tracerController -> tracerController.startTracer(param1));
}
}
...
}
Basically, I want to test if the tracerController.startTracer(param1) is receiving the param1 as argument.
Capture<Object> method1Param1 = newCapture();
tracerController.startTracer(capture(method1Param1));
expectLastCall().once();
...
tracerService.startTracer("TEST", "value1");
assertThat(method1Param1.getValue()).isEqualsTo("value1");
How I can configure EasyMock/PowerMock for that executeOnTracerControllerScope execute tracerController.startTracer without invocating their internal code?
tracerController is a mock. So startTracer won't be called on it. As defined right now, it will simply do nothing. The code doing what you are asking should be something like that:
Capture<Object> method1Param1 = newCapture();
tracerController.startTracer(capture(method1Param1)); // no need for the expect, it's the default
replay(tracerController);
// ...
tracerService.startTracer("TEST", "value1");
assertThat(method1Param1.getValue()).isEqualsTo("value1");
Of course, attendStartConditions and executeOnTracerControllerScope will be called for real.
Following your comment, if you want to mock executeOnTracerControllerScope, you will do the code below. However, your lambda won't be called anymore. So you won't be able to validate the param.
public class MyTest {
#Test
public void test() {
TracerController tracerController = mock(TracerController.class);
TracerService service = partialMockBuilder(TracerService.class)
.withConstructor(tracerController)
.addMockedMethod("executeOnTracerControllerScope")
.mock();
replay(tracerController);
service.startTracer("tracer", "param");
}
}
class TracerService {
private final TracerController tracerController;
public TracerService(TracerController tracerController) {
this.tracerController = tracerController;
}
public boolean attendStartConditions(String tracerName, Object param1) {
return true;
}
public void executeOnTracerControllerScope(Consumer<TracerController> tracer) {
tracer.accept(tracerController);
}
public void startTracer(String tracerName, Object param1) {
if (attendStartConditions(tracerName, param1)) {
executeOnTracerControllerScope(tracerController -> tracerController.startTracer(param1));
}
}
}
interface TracerController {
void startTracer(Object param1);
}
I have multiple test cases and I want to use a single Document variable with all of them.
There are more test units which will use this Document.
I had an idea to download the html code, in order to avoid connecting to the site multiple times and taking up server resources, but still I think that it wouldn't be an optional approach to testing.
public class ScrapperTest {
public ScrapperTest() {
}
#BeforeClass
public static void setUpClass() {
}
#AfterClass
public static void tearDownClass() {
}
#Before
public void setUp() {
}
#After
public void tearDown() {
}
/**
* Test of scrapeManufacturer method, of class Scrapper.
*/
#Test
public void testScrapeManufacturer() {
System.out.println("scrapeManufacturer");
Document html = null;
Scrapper instance = new ScrapperImpl();
String expResult = "";
String result = instance.scrapeManufacturer(html);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
}
/**
* Test of scrapeMinPrice method, of class Scrapper.
*/
#Test
public void testScrapeMinPrice() {
System.out.println("scrapeMinPrice");
Document html = null;
Scrapper instance = new ScrapperImpl();
String expResult = "";
String result = instance.scrapeMinPrice(html);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
Please, help me write a JUnit test for this code using Mockito.
class A{
private BlockingQueue<Runnable> jobQueue;
public void methodA(List<String> messages) {
try {
jobQueue.put(() -> methodB(message));
} catch(InterruptedException e) {}
}
private void methodB(Message message) {
//other logic
}
}
Your example lacks context as to what it is methodB is doing... Without knowing what the functionality is that you want to verify, just verifying that methodB gets called wouldn't be a particularly useful test, nor is mocking the BlockingQueue. I'm going to go out on a limb and assume that methodB interacts with another object, and it's this interaction that you really want to verify, if that's the case my code and test would look something like:
class A {
private BlockingQueue<Runnable> jobQueue;
private B b;
public void methodA(Message message) {
try {
jobQueue.put(() -> methodB(message));
} catch (InterruptedException e) {
}
}
private void methodB(Message message) {
b.sendMethod(message);
}
}
class B {
public void sendMethod(Message message) {
// other logic
}
}
And my test would potentially look something like:
class Atest {
private A testSubject;
#Mock
private B b;
#Test
public void testASendsMessage() {
Message message = new Message("HELLO WORLD");
testSubject.methodA(message);
verify(b, timeout(100)).sendMethod(message);
}
#Before
public void setup() throws Exception {
testSubject = new A();
}
}
In general you want to avoid needing to verifying bits with multiple threads in a unit test, save tests with multiple running threads mainly for integration tests but where it is necessary look at Mockito.timeout(), see example above for how to use. Hopefully this helps?
I have a class with many functions
public class Test {
public void a() {
try {
doSomething1();
} catch (AException e) {
throw new BException(e.getMessage(), e.getCause());
}
}
public void b() {
try {
doSomething2();
} catch (AException e) {
throw new BException(e.getMessage(), e.getCause());
}
}
}
In each method, an exception of certain type is caught and converted to another exception and thrown.
I want to remove duplication.
You may remove duplication using lambda:
The CallableEx takes any exception, in case you are working with checked exception. You would not need it if AException was an unchecked exception. Callable interface won't help you much because it throws an Exception and not your AException: you would have to check for instance and so on.
You could probably write the body instead of this::doSomething1, but I advise against it: this makes the code clearer and it separates concerns.
You could probably also use an annotation processor to do the same job and to rewrite the method in order to wrap your AException into a BException. You would not have duplication in your Java code, but your bytecode certainly will.
Here the example with lambda:
public class Test {
#FunctionalInterface
interface CallableEx<T, E extends Exception> {
T run() throws E;
}
private <T> void handleException(CallableEx<T, AException> forrestGump) {
try {
return forrestGump.run();
} catch (AException e) {
throw new BException(e.getMessage(), e.getCause());
}
}
public String a() {
return handleException(this::doSomething1);
}
public int b(int a, int b) {
return handleException(() -> this.doSomething2(a, b));
}
public <T extends Foobar> void c(T my) {
handleException(() -> this.doSomething3(my));
}
private String doSomething1() {return "A";}
private int doSomething2(int a, int b) {return a + b;}
private <T extends Foobar> void doSomething3(T my) {my.foo();}
}
I have created two observables.
One of them throws an exception.
obs1 = Observable.from(new Integer[]{1, 2, 3, 4, 5, 6});
obs2 = Observable.create(new Observable.OnSubscribe<Integer>() {
#Override public void call(Subscriber<? super Integer> subscriber) {
boolean b = getObj().equals(""); // this throws an exception
System.out.println("1");
}
});
Now I invoke them using
Observable.merge(obs2, obs1)
.subscribe(new Observer<Integer>() {
#Override public void onCompleted() {
System.out.println("onCompleted");
}
#Override public void onError(Throwable throwable) {
System.out.println("onError");
}
#Override public void onNext(Integer integer) {
System.out.println("onNext - " + integer);
}
});
Now, I dont want my process to halt completely when an exception occurs -
I want to handle it and I want obs1 to continue its work.
I have tried to write it using onErrorResumeNext(), onExceptionResumeNext(), doOnError()
but nothing helped - obs1 did not run.
How can I handle the exception without stopping the other observable from being processed?
Sounds like you need mergeDelayError.
The problem is in your subscriber which is broken. You should catch your exception and call onError. Otherwise, you broke the rx contract.
example :
Observable<Integer> obs1 = Observable.from(Arrays.asList(1, 2, 3, 4, 5, 6));
Observable<Integer> obs2 = Observable.create((Subscriber<? super Integer> subscriber) -> {
subscriber.onError(new NullPointerException());
});
Observable.merge(obs2.onErrorResumeNext((e) -> Observable.empty()), obs1)
.subscribe(new Observer<Integer>() {
#Override public void onCompleted() {
System.out.println("onCompleted");
}
#Override public void onError(Throwable throwable) {
System.out.println("onError");
}
#Override public void onNext(Integer integer) {
System.out.println("onNext - " + integer);
}
});
so if you replace your obs2 code with this, it should work like you expected :
obs2 = Observable.create(new Observable.OnSubscribe<Integer>() {
#Override public void call(Subscriber<? super Integer> subscriber) {
try {
boolean b = getObj().equals(""); // this throws an exception
System.out.println("1");
} catch(Exception ex) {
subscriber.onError(ex);
}
}
});