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 static java.util.Arrays.asList; 9 import static java.util.Collections.emptyList; 10 import static org.assertj.core.api.Assertions.assertThat; 11 12 import java.util.List; 13 import org.hamcrest.BaseMatcher; 14 import org.hamcrest.Description; 15 import org.hamcrest.TypeSafeMatcher; 16 import org.junit.Rule; 17 import org.junit.Test; 18 import org.junit.rules.ExpectedException; 19 import org.junit.rules.TestName; 20 import org.junit.runner.RunWith; 21 import org.mockito.Mock; 22 import org.mockito.exceptions.verification.NeverWantedButInvoked; 23 import org.mockito.exceptions.verification.TooLittleActualInvocations; 24 import org.mockito.exceptions.verification.TooManyActualInvocations; 25 import org.mockito.internal.invocation.InvocationBuilder; 26 import org.mockito.internal.invocation.InvocationMatcher; 27 import org.mockito.invocation.Invocation; 28 import org.mockito.junit.MockitoJUnitRunner; 29 import org.mockitousage.IMethods; 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 shouldReportWithLastInvocationStackTrace()61 public void shouldReportWithLastInvocationStackTrace() 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", 2)); 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 shouldReportWithFirstUndesiredInvocationStackTrace()89 public void shouldReportWithFirstUndesiredInvocationStackTrace() 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("" + third.getLocation()); 99 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 2); 100 } 101 102 @Test shouldReportTooManyActual()103 public void shouldReportTooManyActual() throws Exception { 104 Invocation first = buildSimpleMethod().toInvocation(); 105 Invocation second = buildSimpleMethod().toInvocation(); 106 107 invocations = asList(first, second); 108 wanted = buildSimpleMethod().toInvocationMatcher(); 109 110 exception.expectMessage("Wanted 1 time"); 111 exception.expectMessage("But was 2 times"); 112 113 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 1); 114 } 115 116 @Test shouldReportNeverWantedButInvoked()117 public void shouldReportNeverWantedButInvoked() throws Exception { 118 Invocation first = buildSimpleMethod().toInvocation(); 119 120 invocations = asList(first); 121 wanted = buildSimpleMethod().toInvocationMatcher(); 122 123 exception.expect(NeverWantedButInvoked.class); 124 exception.expectMessage("Never wanted here"); 125 exception.expectMessage("But invoked here"); 126 exception.expectMessage("" + first.getLocation()); 127 128 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 0); 129 } 130 131 @Test shouldMarkInvocationsAsVerified()132 public void shouldMarkInvocationsAsVerified() throws Exception { 133 Invocation invocation = buildSimpleMethod().toInvocation(); 134 assertThat(invocation.isVerified()).isFalse(); 135 136 invocations = asList(invocation); 137 wanted = buildSimpleMethod().toInvocationMatcher(); 138 NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 1); 139 assertThat(invocation.isVerified()).isTrue(); 140 } 141 buildSimpleMethod()142 private InvocationBuilder buildSimpleMethod() { 143 return new InvocationBuilder().mock(mock).simpleMethod(); 144 } 145 containsTimes(String value, int amount)146 private static BaseMatcher<String> containsTimes(String value, int amount) { 147 return new StringContainsNumberMatcher(value, amount); 148 } 149 150 private static class StringContainsNumberMatcher extends TypeSafeMatcher<String> { 151 152 private final String expected; 153 154 private final int amount; 155 StringContainsNumberMatcher(String expected, int amount)156 StringContainsNumberMatcher(String expected, int amount) { 157 this.expected = expected; 158 this.amount = amount; 159 } 160 matchesSafely(String text)161 public boolean matchesSafely(String text) { 162 int lastIndex = 0; 163 int count = 0; 164 while (lastIndex != -1) { 165 lastIndex = text.indexOf(expected, lastIndex); 166 if (lastIndex != -1) { 167 count++; 168 lastIndex += expected.length(); 169 } 170 } 171 return count == amount; 172 } 173 describeTo(Description description)174 public void describeTo(Description description) { 175 description.appendText("containing '" + expected + "' exactly " + amount + " times"); 176 } 177 178 } 179 } 180