1 /* 2 * Copyright (c) 2007 Mockito contributors 3 * This program is made available under the terms of the MIT License. 4 */ 5 6 package org.mockito.internal.verification.checkers; 7 8 import java.util.List; 9 import org.hamcrest.BaseMatcher; 10 import org.hamcrest.Description; 11 import org.hamcrest.TypeSafeMatcher; 12 import org.junit.Rule; 13 import org.junit.Test; 14 import org.junit.rules.ExpectedException; 15 import org.junit.rules.TestName; 16 import org.junit.runner.RunWith; 17 import org.mockito.Mock; 18 import org.mockito.exceptions.verification.NeverWantedButInvoked; 19 import org.mockito.exceptions.verification.TooLittleActualInvocations; 20 import org.mockito.exceptions.verification.TooManyActualInvocations; 21 import org.mockito.internal.invocation.InvocationBuilder; 22 import org.mockito.internal.invocation.InvocationMatcher; 23 import org.mockito.invocation.Invocation; 24 import org.mockito.junit.MockitoJUnitRunner; 25 import org.mockitousage.IMethods; 26 27 import static java.util.Arrays.asList; 28 import static java.util.Collections.emptyList; 29 import static org.assertj.core.api.Assertions.assertThat; 30 31 @RunWith(MockitoJUnitRunner.class) 32 public class NumberOfInvocationsCheckerTest { 33 34 private InvocationMatcher wanted; 35 36 private List<Invocation> invocations; 37 38 @Mock 39 private IMethods mock; 40 41 @Rule 42 public ExpectedException exception = ExpectedException.none(); 43 44 @Rule 45 public TestName testName = new TestName(); 46 47 @Test shouldReportTooLittleActual()48 public void shouldReportTooLittleActual() throws Exception { 49 wanted = buildSimpleMethod().toInvocationMatcher(); 50 invocations = asList(buildSimpleMethod().toInvocation(), buildSimpleMethod().toInvocation()); 51 52 exception.expect(TooLittleActualInvocations.class); 53 exception.expectMessage("mock.simpleMethod()"); 54 exception.expectMessage("Wanted 100 times"); 55 exception.expectMessage("But was 2 times"); 56 57 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 100); 58 } 59 60 @Test shouldReportAllInvocationsStackTrace()61 public void shouldReportAllInvocationsStackTrace() throws Exception { 62 wanted = buildSimpleMethod().toInvocationMatcher(); 63 invocations = asList(buildSimpleMethod().toInvocation(), buildSimpleMethod().toInvocation()); 64 65 exception.expect(TooLittleActualInvocations.class); 66 exception.expectMessage("mock.simpleMethod()"); 67 exception.expectMessage("Wanted 100 times"); 68 exception.expectMessage("But was 2 times"); 69 exception.expectMessage(containsTimes("-> at", 3)); 70 71 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 100); 72 } 73 74 @Test shouldNotReportWithLastInvocationStackTraceIfNoInvocationsFound()75 public void shouldNotReportWithLastInvocationStackTraceIfNoInvocationsFound() throws Exception { 76 invocations = emptyList(); 77 wanted = buildSimpleMethod().toInvocationMatcher(); 78 79 exception.expect(TooLittleActualInvocations.class); 80 exception.expectMessage("mock.simpleMethod()"); 81 exception.expectMessage("Wanted 100 times"); 82 exception.expectMessage("But was 0 times"); 83 exception.expectMessage(containsTimes("-> at", 1)); 84 85 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 100); 86 } 87 88 @Test shouldReportWithAllInvocationsStackTrace()89 public void shouldReportWithAllInvocationsStackTrace() throws Exception { 90 Invocation first = buildSimpleMethod().toInvocation(); 91 Invocation second = buildSimpleMethod().toInvocation(); 92 Invocation third = buildSimpleMethod().toInvocation(); 93 94 invocations = asList(first, second, third); 95 wanted = buildSimpleMethod().toInvocationMatcher(); 96 97 exception.expect(TooManyActualInvocations.class); 98 exception.expectMessage("" + first.getLocation()); 99 exception.expectMessage("" + second.getLocation()); 100 exception.expectMessage("" + third.getLocation()); 101 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 2); 102 } 103 104 @Test shouldReportTooManyActual()105 public void shouldReportTooManyActual() throws Exception { 106 Invocation first = buildSimpleMethod().toInvocation(); 107 Invocation second = buildSimpleMethod().toInvocation(); 108 109 invocations = asList(first, second); 110 wanted = buildSimpleMethod().toInvocationMatcher(); 111 112 exception.expectMessage("Wanted 1 time"); 113 exception.expectMessage("But was 2 times"); 114 115 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 1); 116 } 117 118 @Test shouldReportNeverWantedButInvoked()119 public void shouldReportNeverWantedButInvoked() throws Exception { 120 Invocation first = buildSimpleMethod().toInvocation(); 121 122 invocations = asList(first); 123 wanted = buildSimpleMethod().toInvocationMatcher(); 124 125 exception.expect(NeverWantedButInvoked.class); 126 exception.expectMessage("Never wanted here"); 127 exception.expectMessage("But invoked here"); 128 exception.expectMessage("" + first.getLocation()); 129 130 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 0); 131 } 132 133 @Test shouldMarkInvocationsAsVerified()134 public void shouldMarkInvocationsAsVerified() throws Exception { 135 Invocation invocation = buildSimpleMethod().toInvocation(); 136 assertThat(invocation.isVerified()).isFalse(); 137 138 invocations = asList(invocation); 139 wanted = buildSimpleMethod().toInvocationMatcher(); 140 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 1); 141 assertThat(invocation.isVerified()).isTrue(); 142 } 143 buildSimpleMethod()144 private InvocationBuilder buildSimpleMethod() { 145 return new InvocationBuilder().mock(mock).simpleMethod(); 146 } 147 containsTimes(String value, int amount)148 private static BaseMatcher<String> containsTimes(String value, int amount) { 149 return new StringContainsNumberMatcher(value, amount); 150 } 151 152 private static class StringContainsNumberMatcher extends TypeSafeMatcher<String> { 153 154 private final String expected; 155 156 private final int amount; 157 StringContainsNumberMatcher(String expected, int amount)158 StringContainsNumberMatcher(String expected, int amount) { 159 this.expected = expected; 160 this.amount = amount; 161 } 162 matchesSafely(String text)163 public boolean matchesSafely(String text) { 164 int lastIndex = 0; 165 int count = 0; 166 while (lastIndex != -1) { 167 lastIndex = text.indexOf(expected, lastIndex); 168 if (lastIndex != -1) { 169 count++; 170 lastIndex += expected.length(); 171 } 172 } 173 return count == amount; 174 } 175 describeTo(Description description)176 public void describeTo(Description description) { 177 description.appendText("containing '" + expected + "' exactly " + amount + " times"); 178 } 179 180 } 181 } 182