Jukito icon indicating copy to clipboard operation
Jukito copied to clipboard

Jukito does not work well with ExpectedException rule

Open metaschell opened this issue 5 years ago • 2 comments

Using ExpectedException to test for expected exception does not work as intended, as Jukito's InjectedAfterStatements.evaluate() wraps and rethrows all exceptions as org.junit.internal.runners.model.MultipleFailureException.MultipleFailureException(List<Throwable>)

This behavior would be ok for multiple exceptions, e.g. when also catching Guice-related exceptions in addition to exceptions which occurred in the actual test. But when there is only one exception, this should be re-thrown directly instead of wrapping it into MultipleFailureException.

This can actually easily be done by using org.junit.runners.model.MultipleFailureException.assertEmpty(List<Throwable>) which first checks if there is only a single exception and if so rethrows it directly. Multiple exceptions are still wrapped into a MultipleFailureException as it used to be in Jukito.

metaschell avatar Feb 13 '20 08:02 metaschell

A possible workaround is to use a subclass of JukitoRunner which overrides org.jukito.JukitoRunner.withAfters(FrameworkMethod, Object, Statement) with a version creating a subclass of InjectedAfterStatements overriding org.jukito.InjectedAfterStatements.evaluate() to catch any MultipleFailureException and rather directly throw a single exception or otherwise the original MultipleFailureException.

/**
 * Jukito test runner with work around for proper support of ExpectedException.
 * 
 * <p>
 * See <a href="https://github.com/ArcBees/Jukito/issues/83">Jukito does not work well with ExpectedException rule #83</a> for details.
 * </p>
 */
public class MPJukitoRunner extends JukitoRunner {

    public MPJukitoRunner(Class<?> klass, Injector injector)
            throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException {
        super(klass, injector);
    }

    public MPJukitoRunner(Class<?> klass)
            throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException {
        super(klass);
    }
    
    @Override
    protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
        Statement parent = super.withAfters(method, target, statement);
        if (parent instanceof InjectedAfterStatements) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        parent.evaluate();
                    }
                    catch (MultipleFailureException mfe) {
                        // if there was only a single failure, 
                        // rather re-throw that individually
                        MultipleFailureException.assertEmpty(mfe.getFailures());
                    }
                }
            };
        }
        return parent;
    }
}

metaschell avatar Feb 13 '20 08:02 metaschell

+1 Got the same problem

nikitar avatar May 24 '21 04:05 nikitar