Android JUnit Testing … How to Expect an Exception

后端 未结 3 1501
难免孤独
难免孤独 2021-02-04 23:21

I\'m attempting to write some tests using the built-in android Junit testing framework. I am running into a problem with a test where I am expecting an exception to be thrown.

相关标签:
3条回答
  • 2021-02-05 00:02

    The standard junit 3 idiom for this sort of test was:

    public void testThatMethodThrowsException()
    {
      try
      {
        doSomethingThatShouldThrow();
        Assert.fail("Should have thrown Arithmetic exception");
      }
      catch(ArithmeticException e)
      {
        //success
      }
    }
    
    0 讨论(0)
  • 2021-02-05 00:12

    Now JUnit4 is available via Android SDK (refer to android-test-kit)

    Update: it's official now on d.android.com:

    The AndroidJUnitRunner is a new unbundled test runner for Android, which is part of the Android Support Test Library and can be downloaded via the Android Support Repository. The new runner contains all improvements of GoogleInstrumentationTestRunner and adds more features:

    • JUnit4 support
    • Instrumentation Registry for accessing Instrumentation, Context and Bundle Arguments
    • Test Filters @SdkSupress and @RequiresDevice
    • Test timeouts
    • Sharding of tests
    • RunListener support to hook into the test run lifecycle
    • Activity monitoring mechanism ActivityLifecycleMonitorRegistry

    So, JUnit4 style of exception testing using expected annotation:

    @Test(expected= IndexOutOfBoundsException.class) 
    public void empty() { 
         new ArrayList<Object>().get(0); 
    }
    

    or expected exception rules:

    @Rule
    public ExpectedException thrown = ExpectedException.none();
    
    @Test
    public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
        List<Object> list = new ArrayList<Object>();
    
        thrown.expect(IndexOutOfBoundsException.class);
        thrown.expectMessage("Index: 0, Size: 0");
        list.get(0); // execution will never get past this line
    }
    

    is also possible.

    Refer to official documentation for more details on how to setup test support library.

    0 讨论(0)
  • 2021-02-05 00:20

    I've been looking for some good solutions, however, none of the solutions was really satisfying to me. So, I created my own.

    public final void assertThrows(VoidFunction v, Class<? extends Exception> e) {
        try {
            v.call();
        } catch (Exception ex) {
            if (!ex.getClass().equals(e)) {
                Assert.fail();
            }
            // Do nothing, basically succeeds test if same exception was thrown.
            return;
        }
    
        // Fails if no exception is thrown by default.
        Assert.fail();
    }
    

    Where VoidFunction is a simple interface:

    @FunctionalInterface
    public interface VoidFunction {
        void call();
    }
    

    This is used as follows (for example):

    @Test
    public void testFoo() {
        assertThrows(() -> foo.bar(null)), NullPointerException.class);
        assertThrows(() -> foo.setPositiveInt(-5)), IllegalArgumentException.class);
        assertThrows(() -> foo.getObjectAt(-100)), IndexOutOfBoundsException.class);
        assertThrows(new VoidFunction() {
                @Override
                public void call() {
                    foo.getObjectAt(-100);
                }
            }, IndexOutOfBoundsException.class); // Success
        assertThrows(new VoidFunction() {
                    @Override
                    public void call() {
                        throw new Exception();
                    }
                }, NullPointerException.class); // Fail
    
    }
    

    I included one call without using the lambda, this makes it easier to understand code sometimes, at least for me. Simple to use and it allows multiple exception catches in ONE method.

    0 讨论(0)
提交回复
热议问题