JUnit: Possible to 'expect' a wrapped exception?

后端 未结 7 1800
花落未央
花落未央 2020-12-05 12:43

I know that one can define an \'expected\' exception in JUnit, doing:

@Test(expect=MyException.class)
public void someMethod() { ... }


        
相关标签:
7条回答
  • 2020-12-05 13:39

    If you're using the latest version of JUnit you can extend the default test runner to handle this for you (without having to wrap each of your methods in a try/catch block)

    ExtendedTestRunner.java - New test runner:

    public class ExtendedTestRunner extends BlockJUnit4ClassRunner
    {
        public ExtendedTestRunner( Class<?> clazz )
            throws InitializationError
        {
            super( clazz );
        }
    
        @Override
        protected Statement possiblyExpectingExceptions( FrameworkMethod method,
                                                         Object test,
                                                         Statement next )
        {
            ExtendedTest annotation = method.getAnnotation( ExtendedTest.class );
            return expectsCauseException( annotation ) ?
                    new ExpectCauseException( next, getExpectedCauseException( annotation ) ) :
                    super.possiblyExpectingExceptions( method, test, next );
        }
    
        @Override
        protected List<FrameworkMethod> computeTestMethods()
        {
            Set<FrameworkMethod> testMethods = new HashSet<FrameworkMethod>( super.computeTestMethods() );
            testMethods.addAll( getTestClass().getAnnotatedMethods( ExtendedTest.class ) );
            return testMethods;
        }
    
        @Override
        protected void validateTestMethods( List<Throwable> errors )
        {
            super.validateTestMethods( errors );
            validatePublicVoidNoArgMethods( ExtendedTest.class, false, errors );
        }
    
        private Class<? extends Throwable> getExpectedCauseException( ExtendedTest annotation )
        {
            if (annotation == null || annotation.expectedCause() == ExtendedTest.None.class)
                return null;
            else
                return annotation.expectedCause();
        }
    
        private boolean expectsCauseException( ExtendedTest annotation) {
            return getExpectedCauseException(annotation) != null;
        }
    
    }
    

    ExtendedTest.java - annotation to mark test methods with:

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface ExtendedTest
    {
    
        /**
         * Default empty exception
         */
        static class None extends Throwable {
            private static final long serialVersionUID= 1L;
            private None() {
            }
        }
    
        Class<? extends Throwable> expectedCause() default None.class;
    }
    

    ExpectCauseException.java - new JUnit Statement:

    public class ExpectCauseException extends Statement
    {
        private Statement fNext;
        private final Class<? extends Throwable> fExpected;
    
        public ExpectCauseException( Statement next, Class<? extends Throwable> expected )
        {
            fNext= next;
            fExpected= expected;
        }
    
        @Override
        public void evaluate() throws Exception
        {
            boolean complete = false;
            try {
                fNext.evaluate();
                complete = true;
            } catch (Throwable e) {
                if ( e.getCause() == null || !fExpected.isAssignableFrom( e.getCause().getClass() ) )
                {
                    String message = "Unexpected exception cause, expected<"
                                + fExpected.getName() + "> but was<"
                                + ( e.getCause() == null ? "none" : e.getCause().getClass().getName() ) + ">";
                    throw new Exception(message, e);
                }
            }
            if (complete)
                throw new AssertionError( "Expected exception cause: "
                        + fExpected.getName());
        }
    }
    

    Usage:

    @RunWith( ExtendedTestRunner.class )
    public class MyTests
    {
        @ExtendedTest( expectedCause = MyException.class )
        public void someMethod()
        {
            throw new RuntimeException( new MyException() );
        }
    }
    
    0 讨论(0)
提交回复
热议问题