1

Suppose that I have a class like;

public class FooBar {

    public int getMethod(List<String> code){

        if(code.size() > 100)
            throw new Exception;

            return 0;
    }
}

and I have a test class like this;

@RunWith(PowerMockRunner.class)
@PrepareForTest(FooBar.class)
public class FooBarTest{

    FooBar fooBarInstance;

    @Before
    public void setUp() {

        //MockitoAnnotations.initMocks(this);
        fooBarInstance = new FooBar();   
    }

    @Test(expected = Exception.class)
    public void testGetCorrelationListCodesParameter() {

        List<String> codes = Mockito.spy(new ArrayList<String>());
        Mockito.doReturn(150).when(codes).size();
        fooBarInstance.getMethod(codes);
    }
}

How can I make this test method to throw an exception ? I've dealing for hours to do this. Well thanks anyway.

quartaela
  • 2,579
  • 16
  • 63
  • 99

2 Answers2

4

Spying is not needed, mocking is enough. As @David said, also mocking is not needed and not recommended for value object.

Using @Test(expected = Exception.class) has many drawbacks, test can pass when exception is thrown from not expected places. Test is not working but is visible as green.

I prefer BDD style testing with catch-exception.

Reasons for using catch-exceptions

(...) in comparison to the use of try/catch blocks.

  • The test is more concise and easier to read.
  • The test cannot be corrupted by a missing assertion. Assume you forgot to type fail() behind the method call that is expected to throw an exception.

(...) in comparison to test runner-specific mechanisms that catch and verify exceptions.

  • A single test can verify more than one thrown exception.
  • The test can verify the properties of the thrown exception after the exception is caught.
  • The test can specify by which method call the exception must be thrown.
  • The test does not depend on a specific test runner (JUnit4, TestNG).
import static com.googlecode.catchexception.CatchException.caughtException;
import static com.googlecode.catchexception.apis.CatchExceptionAssertJ.*;

public class FooBarTest {

    FooBar sut = new FooBar(); // System Under Test

    @Test
    public void shouldThrowExceptionWhenListHasTooManyElements() {

        when(sut).getMethod(listWithSize(150));

        then(caughtException()).isInstanceOf(Exception.class);
    }

    private List<String> listWithSize(int size) {
        return new ArrayList<String>(Arrays.asList(new String[size]));
    }
}

Full working code for this test: https://gist.github.com/mariuszs/8543918


Not recommended solution with expected and mocking.

@RunWith(MockitoJUnitRunner.class)
public class FooBarTest {

    @Mock
    List<String> codes;

    FooBar fooBarInstance = new FooBar();

    @Test(expected = Exception.class)
    public void shouldThrowExceptionWhenListHasTooManyElements() throws Exception {

        when(codes.size()).thenReturn(150);

        fooBarInstance.getMethod(codes);

    }
}
MariuszS
  • 30,646
  • 12
  • 114
  • 155
  • hi MariuszS is there any important differences between using `PowerMockRunner` and `MockitoJUnitRunner` ?. and thanks a lot for your reply. – quartaela Jan 21 '14 at 17:20
  • 1
    PowerMock is for testing finals and static, legacy code, while Mockito is for testing well designed code. – MariuszS Jan 21 '14 at 17:31
  • Note that what OP wrote - `doReturn(150).when(codes).size();` is fine too. It has the same effect as `when(codes.size()).thenReturn(150);` or `given(codes.size()).willReturn(150);`, and in my opinion is preferable, because it means that you don't have to learn a different syntax for stubbing void methods. – Dawood ibn Kareem Jan 21 '14 at 18:20
  • 1
    In BDD style test keywords given/when/then looks better, whole test is more readable. – MariuszS Jan 21 '14 at 19:05
  • That is entirely a matter of opinion. Most people I've talked to about this find the BDD syntax confusing and unnecessary. – Dawood ibn Kareem Jan 21 '14 at 19:10
  • Probably we know very different people ;) – MariuszS Jan 21 '14 at 19:12
  • So what should I do if have to test final,static etc. code with well designed code ? Because as I understand from the tutorials I cannot use both Runner classes ? – quartaela Jan 21 '14 at 19:28
  • 1
    Split test into two parts (classes) with different Runner. – MariuszS Jan 21 '14 at 19:30
  • Well yeah "the simple is the best" :) So it is convenient to test a class with separate two test classses ? – quartaela Jan 21 '14 at 19:33
  • In general you should test behaviour, not class. Two classes for different behaviours are perfectly fine. Take look at this chapter – MariuszS Jan 21 '14 at 19:36
  • Could you please share the link again ? – quartaela Jan 21 '14 at 19:40
  • http://www.slideshare.net/tomek_k/sample-chapter-of-practical-unit-testing-with-testng-and-mockito – MariuszS Jan 21 '14 at 19:40
  • You don't need to split out your tests, and it doesn't always make logical sense to do so. If you're using a runner that doesn't automatically create the Mockito mocks, you can just call the static [initMocks](http://docs.mockito.googlecode.com/hg/org/mockito/MockitoAnnotations.html#initMocks(java.lang.Object)) method instead of using the runner, to process the Mockito annotations. You may also want to add code for the usage validation, but this is not strictly necessary. – Dawood ibn Kareem Jan 21 '14 at 20:24
  • There is more detail on `MockitoJUnitRunner` versus other runners at http://stackoverflow.com/questions/10806345/runwithmockitojunitrunner-class-vs-mockitoannotations-initmocksthis/10812752#10812752 – Dawood ibn Kareem Jan 21 '14 at 20:26
  • You can also use PowerMockRunner for all tests. PowerMockRunner is using Mockito, so you can mock as usual with MockitoRunner. – MariuszS Jan 21 '14 at 20:26
2

A list is a value object. It's not something we should mock. You can write this whole test without mocking anything, if you're prepared to build a list that has a size in excess of 100.

Also, I prefer to use JUnit's ExpectedException mechanism, because it lets you check which line of the test method threw the exception. This is better than passing an argument to the @Test annotation, which only lets you check that the exception was thrown somewhere within the method.

public class FooBarTest {
    @Rule 
    public ExpectedException exceptionRule = ExpectedException.none();
    private FooBar toTest = new FooBar();

    @Test
    public void getMethodThrowsException_whenListHasTooManyElements() {
        List<String> listWith101Elements = 
            new ArrayList<String>(Arrays.asList(new String[101]));

        exceptionRule.expect(Exception.class);
        toTest.getMethod(listWith101Elements);
    }
}
Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • You are right, but without mock you need to use good name for list like `listWith101Elements`, with mock code is readable without any special naming. Also your `listWith101Elements` has fixed sized, if in `getMethod` we add or remove something from list then whole test will failure - this is bad side effect. – MariuszS Jan 21 '14 at 19:07
  • Well I guess if I initiate a list with 101 objects and pass it, I won't face with any issues and the test will finish successfully. However, should I use Mocking and Spying whenever possible or if passing and testing behaviour of methods with real initialized objects is more easy then should I use the second way ? I mean is there any standart ? – quartaela Jan 21 '14 at 19:32
  • Imagine situation when someone after some time add to `getMethod` this code: `code.add("Foo");`. This was needed for some new features. After this, test and only test throws Exception `java.lang.UnsupportedOperationException`, test will pass because we expect `Exception` but is not testing `size()` any more. This happens because you are testing *fixed-size list backed by the specified array*, this is not normal list. – MariuszS Jan 21 '14 at 20:13
  • Absolutely. In "real life", you wouldn't just throw `new Exception()`, you'd throw `new MySpecificFooBarException("Too many elements in list")` or something similar. The beauty of the `ExpectedException` way of working is that you can check the class of the exception, you can check the message inside the exception, AND you can make sure the exception is thrown at the right place in the test (instead of in the set-up code for example). The old-style `@Test(...)` way of doing it can only check the class of the exception, which is why `ExpectedException` is much better. – Dawood ibn Kareem Jan 21 '14 at 20:18
  • You are right, but it is better when test is less sensitive to changes made in production code. In this case test will fail. – MariuszS Jan 21 '14 at 20:29
  • Yes. Absolutely it's better that way. What I've described won't fail. That's WHY it's better to do it the way I've suggested, than to use `@Test(...)`. – Dawood ibn Kareem Jan 21 '14 at 20:30
  • No David, `Arrays.asList(new String[101])` is the cause of test fail, when we add something to this list in production code. – MariuszS Jan 21 '14 at 20:31
  • Oh, I understand now what you are getting at. OK, but that's not an excuse to use mock a value object. Making a new list is still the better approach. I will edit my answer so that it's a `java.util.ArrayList` instead of a `java.util.Arrays.ArrayList` (which is actually what I had before my first edit). – Dawood ibn Kareem Jan 21 '14 at 20:37
  • Ok, now is much better :) Test is ok, still less readable in my opinion but well written :) – MariuszS Jan 21 '14 at 20:38
  • From the expert (Steve Freeman) on mocking value objects - http://www.mockobjects.com/2007/04/test-smell-everything-is-mocked.html – Dawood ibn Kareem Jan 21 '14 at 20:39
  • If I had a lot of tests in this test class, I would include a helper method for making a list with a certain number of elements, then just write something like `List listWith101Elements = makeStringList(101);` – Dawood ibn Kareem Jan 21 '14 at 20:41
  • I have updated my answer to your recomendations, thanks. – MariuszS Jan 21 '14 at 20:51