Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Duration overloads. Fixes #1815 #1818

Merged
merged 2 commits into from Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
131 changes: 113 additions & 18 deletions src/main/java/org/mockito/Mockito.java
Expand Up @@ -4,6 +4,8 @@
*/
package org.mockito;

import java.time.Duration;

import org.mockito.exceptions.misusing.PotentialStubbingProblem;
import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
import org.mockito.internal.InternalMockHandler;
Expand Down Expand Up @@ -886,15 +888,15 @@
* <pre class="code"><code class="java">
* //passes when someMethod() is called no later than within 100 ms
* //exits immediately when verification is satisfied (e.g. may not wait full 100 ms)
* verify(mock, timeout(100)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100))).someMethod();
* //above is an alias to:
* verify(mock, timeout(100).times(1)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100)).times(1)).someMethod();
*
* //passes as soon as someMethod() has been called 2 times under 100 ms
* verify(mock, timeout(100).times(2)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100)).times(2)).someMethod();
*
* //equivalent: this also passes as soon as someMethod() has been called 2 times under 100 ms
* verify(mock, timeout(100).atLeast(2)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100)).atLeast(2)).someMethod();
* </code></pre>
*
*
Expand Down Expand Up @@ -2830,26 +2832,61 @@ public static VerificationMode only() {
* <pre class="code"><code class="java">
* //passes when someMethod() is called no later than within 100 ms
* //exits immediately when verification is satisfied (e.g. may not wait full 100 ms)
* verify(mock, timeout(100)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100))).someMethod();
kluever marked this conversation as resolved.
Show resolved Hide resolved
* //above is an alias to:
* verify(mock, timeout(100).times(1)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100)).times(1)).someMethod();
*
* //passes as soon as someMethod() has been called 2 times under 100 ms
* verify(mock, timeout(100).times(2)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100)).times(2)).someMethod();
*
* //equivalent: this also passes as soon as someMethod() has been called 2 times under 100 ms
* verify(mock, timeout(100).atLeast(2)).someMethod();
* verify(mock, timeout(Duration.ofMillis(100)).atLeast(2)).someMethod();
* </code></pre>
*
* See examples in javadoc for {@link Mockito} class
*
* @param millis - duration in milliseconds
*
* @return object that allows fluent specification of the verification (times(x), atLeast(y), etc.)
* @deprecated Use {@link #timeout(Duration)} instead.
*/
@CheckReturnValue
@Deprecated
public static VerificationWithTimeout timeout(long millis) {
return new Timeout(millis, VerificationModeFactory.times(1));
return timeout(Duration.ofMillis(millis));
}

/**
* Verification will be triggered over and over until the given amount of time, allowing testing of async code.
* Useful when interactions with the mock object did not happened yet.
* Extensive use of {@code timeout()} method can be a code smell - there are better ways of testing concurrent code.
* <p>
* See also {@link #after(Duration)} method for testing async code.
* Differences between {@code timeout()} and {@code after} are explained in Javadoc for {@link #after(Duration)}.
*
* <pre class="code"><code class="java">
* //passes when someMethod() is called no later than within 100 ms
* //exits immediately when verification is satisfied (e.g. may not wait full 100 ms)
* verify(mock, timeout(Duration.ofMillis(100))).someMethod();
* //above is an alias to:
* verify(mock, timeout(Duration.ofMillis(100)).times(1)).someMethod();
*
* //passes as soon as someMethod() has been called 2 times under 100 ms
* verify(mock, timeout(Duration.ofMillis(100)).times(2)).someMethod();
*
* //equivalent: this also passes as soon as someMethod() has been called 2 times under 100 ms
* verify(mock, timeout(Duration.ofMillis(100)).atLeast(2)).someMethod();
* </code></pre>
*
* See examples in javadoc for {@link Mockito} class
*
* @param timeout how long to wait before timing out
*
* @return object that allows fluent specification of the verification (times(x), atLeast(y), etc.)
*/
@CheckReturnValue
public static VerificationWithTimeout timeout(Duration timeout) {
return new Timeout(timeout, VerificationModeFactory.times(1));
}

/**
Expand All @@ -2864,19 +2901,19 @@ public static VerificationWithTimeout timeout(long millis) {
*
* <pre class="code"><code class="java">
* //passes after 100ms, if someMethod() has only been called once at that time.
* verify(mock, after(100)).someMethod();
* verify(mock, after(Duration.ofMillis(100))).someMethod();
kluever marked this conversation as resolved.
Show resolved Hide resolved
* //above is an alias to:
* verify(mock, after(100).times(1)).someMethod();
* verify(mock, after(Duration.ofMillis(100)).times(1)).someMethod();
*
* //passes if someMethod() is called <b>*exactly*</b> 2 times, as tested after 100 millis
* verify(mock, after(100).times(2)).someMethod();
* verify(mock, after(Duration.ofMillis(100)).times(2)).someMethod();
*
* //passes if someMethod() has not been called, as tested after 100 millis
* verify(mock, after(100).never()).someMethod();
* verify(mock, after(Duration.ofMillis(100)).never()).someMethod();
*
* //verifies someMethod() after a given time span using given verification mode
* //useful only if you have your own custom verification modes.
* verify(mock, new After(100, yourOwnVerificationMode)).someMethod();
* verify(mock, new After(Duration.ofMillis(100), yourOwnVerificationMode)).someMethod();
* </code></pre>
*
* <strong>timeout() vs. after()</strong>
Expand All @@ -2888,12 +2925,12 @@ public static VerificationWithTimeout timeout(long millis) {
* <pre class="code"><code class="java">
* //1.
* mock.foo();
* verify(mock, after(1000)).foo();
* //waits 1000 millis and succeeds
* verify(mock, after(Duration.ofSeconds(1))).foo();
* //waits 1 second and succeeds
*
* //2.
* mock.foo();
* verify(mock, timeout(1000)).foo();
* verify(mock, timeout(Duration.ofSeconds(1))).foo();
* //succeeds immediately
* </code></pre>
*
Expand All @@ -2902,10 +2939,68 @@ public static VerificationWithTimeout timeout(long millis) {
* @param millis - duration in milliseconds
*
* @return object that allows fluent specification of the verification
* @deprecated Use {@link #after(Duration)} instead.
*/
@CheckReturnValue
@Deprecated
public static VerificationAfterDelay after(long millis) {
return new After(millis, VerificationModeFactory.times(1));
return after(Duration.ofMillis(millis));
}

/**
* Verification will be triggered after given amount of time, allowing testing of async code.
* Useful when interactions with the mock object did not happened yet.
* Extensive use of {@code after()} method can be a code smell - there are better ways of testing concurrent code.
* <p>
* Not yet implemented to work with InOrder verification.
* <p>
* See also {@link #timeout(Duration)} method for testing async code.
* Differences between {@code timeout()} and {@code after()} are explained below.
*
* <pre class="code"><code class="java">
* //passes after 100ms, if someMethod() has only been called once at that time.
* verify(mock, after(Duration.ofMillis(100))).someMethod();
* //above is an alias to:
* verify(mock, after(Duration.ofMillis(100)).times(1)).someMethod();
*
* //passes if someMethod() is called <b>*exactly*</b> 2 times, as tested after 100 millis
* verify(mock, after(Duration.ofMillis(100)).times(2)).someMethod();
*
* //passes if someMethod() has not been called, as tested after 100 millis
* verify(mock, after(Duration.ofMillis(100)).never()).someMethod();
*
* //verifies someMethod() after a given time span using given verification mode
* //useful only if you have your own custom verification modes.
* verify(mock, new After(Duration.ofMillis(100), yourOwnVerificationMode)).someMethod();
* </code></pre>
*
* <strong>timeout() vs. after()</strong>
* <ul>
* <li>timeout() exits immediately with success when verification passes</li>
* <li>after() awaits full duration to check if verification passes</li>
* </ul>
* Examples:
* <pre class="code"><code class="java">
* //1.
* mock.foo();
* verify(mock, after(Duration.ofSeconds(1))).foo();
* //waits 1 second and succeeds
*
* //2.
* mock.foo();
* verify(mock, timeout(Duration.ofSeconds(1))).foo();
* //succeeds immediately
* </code></pre>
*
* See examples in javadoc for {@link Mockito} class
*
* @param delay how to to wait before triggering verification
*
* @return object that allows fluent specification of the verification
*/
@CheckReturnValue
public static VerificationAfterDelay after(Duration delay) {
return new After(delay, VerificationModeFactory.times(1));
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/mockito/internal/exceptions/Reporter.java
Expand Up @@ -10,6 +10,7 @@

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -863,12 +864,12 @@ public static MockitoException usingConstructorWithFancySerializable(Serializabl
return new MockitoException("Mocks instantiated with constructor cannot be combined with " + mode + " serialization mode.");
}

public static MockitoException cannotCreateTimerWithNegativeDurationTime(long durationMillis) {
public static MockitoException cannotCreateTimerWithNegativeDurationTime(Duration duration) {
return new FriendlyReminderException(join(
"",
"Don't panic! I'm just a friendly reminder!",
"It is impossible for time to go backward, therefore...",
"You cannot put negative value of duration: (" + durationMillis + ")",
"You cannot put negative value of duration: (" + duration + ")",
"as argument of timer methods (after(), timeout())",
""
));
Expand Down
22 changes: 12 additions & 10 deletions src/main/java/org/mockito/internal/util/Timer.java
Expand Up @@ -6,22 +6,24 @@

import static org.mockito.internal.exceptions.Reporter.cannotCreateTimerWithNegativeDurationTime;

import java.time.Duration;

public class Timer {

private final long durationMillis;
private final Duration duration;
private long startTime = -1;

public Timer(long durationMillis) {
validateInput(durationMillis);
this.durationMillis = durationMillis;
public Timer(Duration duration) {
validateInput(duration);
this.duration = duration;
}

/**
* Informs whether the timer is still counting down.
*/
public boolean isCounting() {
assert startTime != -1;
return System.currentTimeMillis() - startTime <= durationMillis;
return System.currentTimeMillis() - startTime <= duration.toMillis();
kluever marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand All @@ -31,13 +33,13 @@ public void start() {
startTime = System.currentTimeMillis();
}

private void validateInput(long durationMillis) {
if (durationMillis < 0) {
throw cannotCreateTimerWithNegativeDurationTime(durationMillis);
private void validateInput(Duration duration) {
if (duration.isNegative()) {
throw cannotCreateTimerWithNegativeDurationTime(duration);
}
}

public long duration() {
return durationMillis;
public Duration duration() {
return duration;
}
}
Expand Up @@ -4,51 +4,53 @@
*/
package org.mockito.internal.verification;

import java.time.Duration;

import org.mockito.exceptions.base.MockitoAssertionError;
import org.mockito.internal.util.Timer;
import org.mockito.internal.verification.api.VerificationData;
import org.mockito.verification.VerificationMode;

/**
* Verifies that another verification mode (the delegate) is satisfied within a certain timeframe
* (before timeoutMillis has passed, measured from the call to verify()), and either returns immediately
* (before timeout has passed, measured from the call to verify()), and either returns immediately
* once it does, or waits until it is definitely satisfied once the full time has passed.
*/
public class VerificationOverTimeImpl implements VerificationMode {

private final long pollingPeriodMillis;
private final Duration pollingPeriod;
private final VerificationMode delegate;
private final boolean returnOnSuccess;
private final Timer timer;

/**
* Create this verification mode, to be used to verify invocation ongoing data later.
*
* @param pollingPeriodMillis The frequency to poll delegate.verify(), to check whether the delegate has been satisfied
* @param durationMillis The max time to wait (in millis) for the delegate verification mode to be satisfied
* @param pollingPeriod The frequency to poll delegate.verify(), to check whether the delegate has been satisfied
* @param duration The max time to wait for the delegate verification mode to be satisfied
* @param delegate The verification mode to delegate overall success or failure to
* @param returnOnSuccess Whether to immediately return successfully once the delegate is satisfied (as in
* {@link org.mockito.verification.VerificationWithTimeout}, or to only return once
* the delegate is satisfied and the full duration has passed (as in
* {@link org.mockito.verification.VerificationAfterDelay}).
*/
public VerificationOverTimeImpl(long pollingPeriodMillis, long durationMillis, VerificationMode delegate, boolean returnOnSuccess) {
this(pollingPeriodMillis, delegate, returnOnSuccess, new Timer(durationMillis));
public VerificationOverTimeImpl(Duration pollingPeriod, Duration duration, VerificationMode delegate, boolean returnOnSuccess) {
this(pollingPeriod, delegate, returnOnSuccess, new Timer(duration));
}

/**
* Create this verification mode, to be used to verify invocation ongoing data later.
*
* @param pollingPeriodMillis The frequency to poll delegate.verify(), to check whether the delegate has been satisfied
* @param pollingPeriod The frequency to poll delegate.verify(), to check whether the delegate has been satisfied
* @param delegate The verification mode to delegate overall success or failure to
* @param returnOnSuccess Whether to immediately return successfully once the delegate is satisfied (as in
* {@link org.mockito.verification.VerificationWithTimeout}, or to only return once
* the delegate is satisfied and the full duration has passed (as in
* {@link org.mockito.verification.VerificationAfterDelay}).
* @param timer Checker of whether the duration of the verification is still acceptable
*/
public VerificationOverTimeImpl(long pollingPeriodMillis, VerificationMode delegate, boolean returnOnSuccess, Timer timer) {
this.pollingPeriodMillis = pollingPeriodMillis;
public VerificationOverTimeImpl(Duration pollingPeriod, VerificationMode delegate, boolean returnOnSuccess, Timer timer) {
this.pollingPeriod = pollingPeriod;
this.delegate = delegate;
this.returnOnSuccess = returnOnSuccess;
this.timer = timer;
Expand Down Expand Up @@ -97,7 +99,7 @@ public void verify(VerificationData data) {

private AssertionError handleVerifyException(AssertionError e) {
if (canRecoverFromFailure(delegate)) {
sleep(pollingPeriodMillis);
sleep(pollingPeriod);
return e;
} else {
throw e;
Expand All @@ -109,12 +111,12 @@ protected boolean canRecoverFromFailure(VerificationMode verificationMode) {
}

public VerificationOverTimeImpl copyWithVerificationMode(VerificationMode verificationMode) {
return new VerificationOverTimeImpl(pollingPeriodMillis, timer.duration(), verificationMode, returnOnSuccess);
return new VerificationOverTimeImpl(pollingPeriod, timer.duration(), verificationMode, returnOnSuccess);
}

private void sleep(long sleep) {
private void sleep(Duration sleep) {
try {
Thread.sleep(sleep);
Thread.sleep(sleep.toMillis());
} catch (InterruptedException ie) {
throw new RuntimeException("Thread sleep has been interrupted", ie);
}
Expand All @@ -124,8 +126,8 @@ public boolean isReturnOnSuccess() {
return returnOnSuccess;
}

public long getPollingPeriodMillis() {
return pollingPeriodMillis;
public Duration getPollingPeriod() {
return pollingPeriod;
}

public Timer getTimer() {
Expand Down
Expand Up @@ -35,7 +35,7 @@ private VerificationMode wrapInOrder(VerificationWrapper<?> verificationWrapper,
if (verificationMode instanceof VerificationOverTimeImpl) {
final VerificationOverTimeImpl verificationOverTime = (VerificationOverTimeImpl)verificationMode;
if (verificationOverTime.isReturnOnSuccess()) {
return new VerificationOverTimeImpl(verificationOverTime.getPollingPeriodMillis(),
return new VerificationOverTimeImpl(verificationOverTime.getPollingPeriod(),
verificationOverTime.getTimer().duration(),
wrapInOrder(verificationWrapper, verificationOverTime.getDelegate(), inOrder),
verificationOverTime.isReturnOnSuccess());
Expand Down