Home | History | Annotate | Download | only in junitrule
      1 package org.mockitousage.junitrule;
      2 
      3 import org.assertj.core.api.Assertions;
      4 import org.junit.Rule;
      5 import org.junit.Test;
      6 import org.mockito.Mock;
      7 import org.mockito.quality.Strictness;
      8 import org.mockito.exceptions.misusing.PotentialStubbingProblem;
      9 import org.mockito.exceptions.misusing.UnfinishedVerificationException;
     10 import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
     11 import org.mockito.junit.MockitoJUnit;
     12 import org.mockitousage.IMethods;
     13 import org.mockitoutil.SafeJUnitRule;
     14 
     15 import static org.junit.Assert.assertEquals;
     16 import static org.mockito.BDDMockito.given;
     17 import static org.mockito.BDDMockito.willReturn;
     18 import static org.mockito.Mockito.*;
     19 import static org.mockitoutil.TestBase.filterLineNo;
     20 
     21 public class StrictJUnitRuleTest {
     22 
     23     @Rule public SafeJUnitRule rule = new SafeJUnitRule(MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS));
     24 
     25     @Mock IMethods mock;
     26     @Mock IMethods mock2;
     27 
     28     @Test public void ok_when_no_stubbings() throws Throwable {
     29         mock.simpleMethod();
     30         verify(mock).simpleMethod();
     31     }
     32 
     33     @Test public void ok_when_all_stubbings_used() throws Throwable {
     34         given(mock.simpleMethod(10)).willReturn("foo");
     35         mock.simpleMethod(10);
     36     }
     37 
     38     @Test public void ok_when_used_and_mismatched_argument() throws Throwable {
     39         given(mock.simpleMethod(10)).willReturn("foo");
     40         mock.simpleMethod(10);
     41         mock.simpleMethod(15);
     42     }
     43 
     44     @Test public void fails_when_unused_stubbings() throws Throwable {
     45         //expect
     46         rule.expectFailure(UnnecessaryStubbingException.class);
     47 
     48         //when
     49         given(mock.simpleMethod(10)).willReturn("foo");
     50         mock2.simpleMethod(10);
     51     }
     52 
     53     @Test public void test_failure_trumps_unused_stubbings() throws Throwable {
     54         //expect
     55         rule.expectFailure(AssertionError.class, "x");
     56 
     57         //when
     58         given(mock.simpleMethod(10)).willReturn("foo");
     59         mock.otherMethod();
     60 
     61         throw new AssertionError("x");
     62     }
     63 
     64     @Test public void why_do_return_syntax_is_useful() throws Throwable {
     65         //Trade-off of Mockito strictness documented in test
     66 
     67         //expect
     68         rule.expectFailure(PotentialStubbingProblem.class);
     69 
     70         //when
     71         when(mock.simpleMethod(10)).thenReturn("10");
     72         when(mock.simpleMethod(20)).thenReturn("20");
     73     }
     74 
     75     @Test public void fails_fast_when_stubbing_invoked_with_different_argument() throws Throwable {
     76         //expect
     77         rule.expectFailure(new SafeJUnitRule.FailureAssert() {
     78             public void doAssert(Throwable t) {
     79                 Assertions.assertThat(t).isInstanceOf(PotentialStubbingProblem.class);
     80                 assertEquals(filterLineNo("\n" +
     81                                 "Strict stubbing argument mismatch. Please check:\n" +
     82                                 " - this invocation of 'simpleMethod' method:\n" +
     83                                 "    mock.simpleMethod(15);\n" +
     84                                 "    -> at org.mockitousage.junitrule.StrictJUnitRuleTest.fails_fast_when_stubbing_invoked_with_different_argument(StrictJUnitRuleTest.java:0)\n" +
     85                                 " - has following stubbing(s) with different arguments:\n" +
     86                                 "    1. mock.simpleMethod(20);\n" +
     87                                 "      -> at org.mockitousage.junitrule.StrictJUnitRuleTest.fails_fast_when_stubbing_invoked_with_different_argument(StrictJUnitRuleTest.java:0)\n" +
     88                                 "    2. mock.simpleMethod(30);\n" +
     89                                 "      -> at org.mockitousage.junitrule.StrictJUnitRuleTest.fails_fast_when_stubbing_invoked_with_different_argument(StrictJUnitRuleTest.java:0)\n" +
     90                                 "Typically, stubbing argument mismatch indicates user mistake when writing tests.\n" +
     91                                 "Mockito fails early so that you can debug potential problem easily.\n" +
     92                                 "However, there are legit scenarios when this exception generates false negative signal:\n" +
     93                                 "  - stubbing the same method multiple times using 'given().will()' or 'when().then()' API\n" +
     94                                 "    Please use 'will().given()' or 'doReturn().when()' API for stubbing.\n" +
     95                                 "  - stubbed method is intentionally invoked with different arguments by code under test\n" +
     96                                 "    Please use 'default' or 'silent' JUnit Rule.\n" +
     97                                 "For more information see javadoc for PotentialStubbingProblem class."),
     98                         filterLineNo(t.getMessage()));
     99             }
    100         });
    101 
    102         //when stubbings in the test code:
    103         willReturn("10").given(mock).simpleMethod(10) ;  //used
    104         willReturn("20").given(mock).simpleMethod(20) ;  //unused
    105         willReturn("30").given(mock).simpleMethod(30) ;  //unused
    106 
    107         //then
    108         mock.otherMethod(); //ok, different method
    109         mock.simpleMethod(10); //ok, stubbed with this argument
    110 
    111         //invocation in the code under test uses different argument and should fail immediately
    112         //this helps with debugging and is essential for Mockito strictness
    113         mock.simpleMethod(15);
    114     }
    115 
    116     @Test public void verify_no_more_interactions_ignores_stubs() throws Throwable {
    117         //when stubbing in test:
    118         given(mock.simpleMethod(10)).willReturn("foo");
    119 
    120         //and code under test does:
    121         mock.simpleMethod(10); //implicitly verifies the stubbing
    122         mock.otherMethod();
    123 
    124         //and in test we:
    125         verify(mock).otherMethod();
    126         verifyNoMoreInteractions(mock);
    127     }
    128 
    129     @Test public void unused_stubs_with_multiple_mocks() throws Throwable {
    130         //expect
    131         rule.expectFailure(new SafeJUnitRule.FailureAssert() {
    132             public void doAssert(Throwable t) {
    133                 assertEquals(filterLineNo("\n" +
    134                         "Unnecessary stubbings detected.\n" +
    135                         "Clean & maintainable test code requires zero unnecessary code.\n" +
    136                         "Following stubbings are unnecessary (click to navigate to relevant line of code):\n" +
    137                         "  1. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
    138                         "  2. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
    139                         "Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class."), filterLineNo(t.getMessage()));
    140             }
    141         });
    142 
    143         //when test has
    144         given(mock.simpleMethod(10)).willReturn("foo");
    145         given(mock2.simpleMethod(20)).willReturn("foo");
    146 
    147         given(mock.otherMethod()).willReturn("foo"); //used and should not be reported
    148 
    149         //and code has
    150         mock.otherMethod();
    151         mock2.booleanObjectReturningMethod();
    152     }
    153 
    154     @Test public void rule_validates_mockito_usage() throws Throwable {
    155         //expect
    156         rule.expectFailure(UnfinishedVerificationException.class);
    157 
    158         //when test contains unfinished verification
    159         verify(mock);
    160     }
    161 }
    162