Skip to main content

Interaction count

Describes the possible expectations for verifying how often an interaction with a mock happened.

ExpectationNegatedSummary
Oncethe interaction happened exactly once
Twicethe interaction happened exactly twice
Neverthe interaction never happened
AtLeastOncethe interaction happened at least once
AtLeastTwicethe interaction happened at least twice
AtLeastthe interaction happened at least the given number of times
AtMostOncethe interaction happened at most once
AtMostTwicethe interaction happened at most twice
AtMostthe interaction happened at most the given number of times
Exactlythe interaction happened exactly the given number of times
Betweenthe number of interactions is in the given range
Timesthe number of interactions satisfies a predicate

The samples use the following interface:

public interface IPlayer
{
bool Play(string title);
void Pause();
void Stop();
}

Number of interactions​

You can verify how often a method was invoked:

using aweXpect.Core; // for Times()
using static aweXpect.Expect;

IPlayer player = IPlayer.CreateMock();
player.Play("Let It Be");

await That(player.Mock.Verify.Play("Let It Be")).Once();
await That(player.Mock.Verify.Play("Yesterday")).Never();
await That(player.Mock.Verify.Play(It.IsAny<string>())).AtLeastOnce();
await That(player.Mock.Verify.Play(It.IsAny<string>())).AtMost(3.Times());
await That(player.Mock.Verify.Play(It.IsAny<string>())).Between(1).And(3.Times());
await That(player.Mock.Verify.Play(It.IsAny<string>())).Times(n => n % 2 == 1);

When the track was played twice, Once() fails with:

Failure message
Expected that the MusicStore.IPlayer mock
invoked method Play(Let It Be) exactly once,
but it was found twice

Matching Interactions:
[
invoke method Play(Let It Be),
invoke method Play(Let It Be)
]

All Interactions:
[
invoke method Play(Let It Be),
invoke method Play(Let It Be)
]

Waiting for interactions​

With Within(TimeSpan timeout), you can verify that the expected number of interactions happens within the given time. This is useful for interactions that happen asynchronously in the background.

Within is available on AtLeast…, Once, Twice, Exactly, Between and Times. It is not available on Never or AtMost…, since an upper bound cannot be confirmed by waiting longer. For the order of interactions, see Then.

IPlayer player = IPlayer.CreateMock();

_ = Task.Run(async () =>
{
await Task.Delay(500);
player.Play("Hey Jude");
});

await That(player.Mock.Verify.Play("Hey Jude")).AtLeastOnce().Within(TimeSpan.FromSeconds(1));

When the interaction does not happen in time, e.g. a Stop() expected within 100 ms, the expectation fails:

Failure message
Expected that the MusicStore.IPlayer mock
invoked method Stop() at least once within 0:00.100,
but it was never found

Matching Interactions:
[]

All Interactions:
[
invoke method Play(Hey Jude)
]

Instead of a fixed time span, you can also provide a CancellationToken to wait for the expected interactions until it is canceled. Like for all aweXpect expectations, a cancellation leaves the expectation inconclusive instead of failing it, so use Within to limit how long the verification waits:

await That(player.Mock.Verify.Play("Hey Jude")).AtLeastOnce().WithCancellation(token);
Waiting without Within

Unlike other aweXpect expectations, these verifications also wait for the interaction when only WithTimeout or WithCancellation is given: the timeout or the token bounds how long they wait, and the verification fails when the timeout elapses. Within sets an explicit wait, which is shown in the expectation; a shorter WithTimeout still ends it early with "it did not finish within …".

note

A Times predicate that throws counts as not met while waiting, so the verification waits for further interactions, and only fails with the exception when the predicate still throws at the end. A selector of Then that throws fails the verification immediately.

Waiting for an interaction not to happen​

DoesNotComplyWith evaluates the verification inside it non-negated, so put Within on the verification inside it to verify that an interaction does not happen within the given time. It waits the whole time and fails as soon as the interaction happens:

await That(player.Mock.Verify.Stop()).DoesNotComplyWith(it => it.AtLeastOnce().Within(TimeSpan.FromSeconds(1)));
warning

Within on DoesNotComplyWith itself does not help here: it only checks again until the interaction is not found, so it succeeds immediately when the interaction did not happen yet.