blob: f4e3e95eeb2ef5d2f73a17e61a4c131501628982 [file] [log] [blame]
/*
* Copyright (c) 2017 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockitousage.junitrule;
import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.exceptions.misusing.PotentialStubbingProblem;
import org.mockito.exceptions.misusing.UnfinishedVerificationException;
import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
import org.mockito.junit.MockitoJUnit;
import org.mockito.quality.Strictness;
import org.mockitousage.IMethods;
import org.mockitoutil.SafeJUnitRule;
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockitoutil.TestBase.filterLineNo;
public class StrictJUnitRuleTest {
@Rule public SafeJUnitRule rule = new SafeJUnitRule(MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS));
@Mock IMethods mock;
@Mock IMethods mock2;
@Test public void ok_when_no_stubbings() throws Throwable {
mock.simpleMethod();
verify(mock).simpleMethod();
}
@Test public void ok_when_all_stubbings_used() throws Throwable {
given(mock.simpleMethod(10)).willReturn("foo");
mock.simpleMethod(10);
}
@Test public void ok_when_used_and_mismatched_argument() throws Throwable {
given(mock.simpleMethod(10)).willReturn("foo");
mock.simpleMethod(10);
mock.simpleMethod(15);
}
@Test public void fails_when_unused_stubbings() throws Throwable {
//expect
rule.expectFailure(UnnecessaryStubbingException.class);
//when
given(mock.simpleMethod(10)).willReturn("foo");
mock2.simpleMethod(10);
}
@Test public void test_failure_trumps_unused_stubbings() throws Throwable {
//expect
rule.expectFailure(AssertionError.class, "x");
//when
given(mock.simpleMethod(10)).willReturn("foo");
mock.otherMethod();
throw new AssertionError("x");
}
@Test public void why_do_return_syntax_is_useful() throws Throwable {
//Trade-off of Mockito strictness documented in test
//expect
rule.expectFailure(PotentialStubbingProblem.class);
//when
when(mock.simpleMethod(10)).thenReturn("10");
when(mock.simpleMethod(20)).thenReturn("20");
}
@Test public void fails_fast_when_stubbing_invoked_with_different_argument() throws Throwable {
//expect
rule.expectFailure(new SafeJUnitRule.FailureAssert() {
public void doAssert(Throwable t) {
Assertions.assertThat(t).isInstanceOf(PotentialStubbingProblem.class);
assertEquals(filterLineNo("\n" +
"Strict stubbing argument mismatch. Please check:\n" +
" - this invocation of 'simpleMethod' method:\n" +
" mock.simpleMethod(15);\n" +
" -> at org.mockitousage.junitrule.StrictJUnitRuleTest.fails_fast_when_stubbing_invoked_with_different_argument(StrictJUnitRuleTest.java:0)\n" +
" - has following stubbing(s) with different arguments:\n" +
" 1. mock.simpleMethod(20);\n" +
" -> at org.mockitousage.junitrule.StrictJUnitRuleTest.fails_fast_when_stubbing_invoked_with_different_argument(StrictJUnitRuleTest.java:0)\n" +
" 2. mock.simpleMethod(30);\n" +
" -> at org.mockitousage.junitrule.StrictJUnitRuleTest.fails_fast_when_stubbing_invoked_with_different_argument(StrictJUnitRuleTest.java:0)\n" +
"Typically, stubbing argument mismatch indicates user mistake when writing tests.\n" +
"Mockito fails early so that you can debug potential problem easily.\n" +
"However, there are legit scenarios when this exception generates false negative signal:\n" +
" - stubbing the same method multiple times using 'given().will()' or 'when().then()' API\n" +
" Please use 'will().given()' or 'doReturn().when()' API for stubbing.\n" +
" - stubbed method is intentionally invoked with different arguments by code under test\n" +
" Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).\n" +
"For more information see javadoc for PotentialStubbingProblem class."),
filterLineNo(t.getMessage()));
}
});
//when stubbings in the test code:
willReturn("10").given(mock).simpleMethod(10) ; //used
willReturn("20").given(mock).simpleMethod(20) ; //unused
willReturn("30").given(mock).simpleMethod(30) ; //unused
//then
mock.otherMethod(); //ok, different method
mock.simpleMethod(10); //ok, stubbed with this argument
//invocation in the code under test uses different argument and should fail immediately
//this helps with debugging and is essential for Mockito strictness
mock.simpleMethod(15);
}
@Test public void verify_no_more_interactions_ignores_stubs() throws Throwable {
//when stubbing in test:
given(mock.simpleMethod(10)).willReturn("foo");
//and code under test does:
mock.simpleMethod(10); //implicitly verifies the stubbing
mock.otherMethod();
//and in test we:
verify(mock).otherMethod();
verifyNoMoreInteractions(mock);
}
@Test public void unused_stubs_with_multiple_mocks() throws Throwable {
//expect
rule.expectFailure(new SafeJUnitRule.FailureAssert() {
public void doAssert(Throwable t) {
assertEquals(filterLineNo("\n" +
"Unnecessary stubbings detected.\n" +
"Clean & maintainable test code requires zero unnecessary code.\n" +
"Following stubbings are unnecessary (click to navigate to relevant line of code):\n" +
" 1. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
" 2. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
"Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class."), filterLineNo(t.getMessage()));
}
});
//when test has
given(mock.simpleMethod(10)).willReturn("foo");
given(mock2.simpleMethod(20)).willReturn("foo");
given(mock.otherMethod()).willReturn("foo"); //used and should not be reported
//and code has
mock.otherMethod();
mock2.booleanObjectReturningMethod();
}
@Test public void rule_validates_mockito_usage() throws Throwable {
//expect
rule.expectFailure(UnfinishedVerificationException.class);
//when test contains unfinished verification
verify(mock);
}
}