0

I've a JUnit which I want to use to test for exceptions. It's like this:

@Test
public void test1() throws Exception {
  boolean testPass;
  try {
    method1();
    testPass = true;
    Assert.assertTrue(testPass);
  }
  catch(Exception e) {
    testPass = false;
    Assert.assertTrue(testPass);
  }
  System.out.println("End of test2 Junit");
}

method1() is like this:

public void method1() throws Exception {
  try {
    do something....
    method2();
  } catch (Exception e) {
    throw e;
  } finally {
   do some more...
  }
}

For what I want, my test is fine when just considering method1(). My problem is that method2() is called by method1() and can also throw an exception. It's like this:

private  void method2() throws Exception {
  if (confition is not met) {
    do something...
    throw new Exception();
  } else {
    do something else;
  }
}

It's possible that no exception is thrown by method1() but then gets thrown by method2(). I'd like my test to check for an exception from either but I'm not sure how to factor method2() into my test, especially as it's a private void method. Can this be done and if so, how?

pac
  • 491
  • 1
  • 7
  • 30
  • What do you mean `factor method2() into my test`? Do you want to test logic of `method2()` along with `method1()` or not? – tsolakp Feb 01 '18 at 23:12
  • If its possible, all I want is for an assertTrue to pass if no exception is thrown in either `method1()` or `method2()` and for it to fail if an exception is thrown by either `method1()` or `method2()`. – pac Feb 01 '18 at 23:15
  • In that case your test will fail if `method2()` throws `Exception` or any of its subclasses. – tsolakp Feb 01 '18 at 23:17
  • 2
    You should be testing the *public* interface, not private implementation. Unit testing should be black-box, in that the tests focus on what occurs from a user perspective. Since the user can't call `method2()`, there should be no reason to test it. The tests exists to ensure the implementation gives excepted results. If `method2()` throws an exception which `method1()` swallows, then the user shouldn't be aware of that exception in the first place. Why are you testing for it? Did you leak details of `method2()` into the contract of `method1()`? If so, THAT'S the problem. – Vince Feb 01 '18 at 23:20
  • Ah, OK. Thanks for that. – pac Feb 01 '18 at 23:24
  • No problem. Check out [this](https://stackoverflow.com/questions/105007/should-i-test-private-methods-or-only-public-ones) & [this](https://www.quora.com/Should-you-unit-test-private-methods-on-a-class) – Vince Feb 01 '18 at 23:27
  • Great. I'll have a read. – pac Feb 01 '18 at 23:28

1 Answers1

1

According to your code it is possible only if you can achieve true condition in this if:

  if (condition is not met) {
    do something...
    throw new Exception();
  } else {
    do something else;
  }

If for some reasons you couldn't prepare such kind of condition in the unit tests (say, Internet connection is needed) you may extract the condition checking into new method:

  if (isNotCondition()) {
    do something...
    throw new Exception();

In the test class you override new method and return what you want:

MyService myService = new MyService() {
    @Override
    boolean isNotCondition() {
        return true;
    }
}

This is more compact way to test exceptional cases:

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testMethod1WhenMethod2ThrowsException() throws Exception {
    thrown.expect(Exception.class);
    thrown.expectMessage("expected exception message");

    myServive.method1();
}
Dmytro Maslenko
  • 2,247
  • 9
  • 16