Advanced callback features
Conditional callbacks (When)
Execute callbacks conditionally based on the zero-based invocation counter using .When():
sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny<int>())
.Do(() => Console.WriteLine("Called!")).When(count => count >= 2); // The first two calls are skipped
Limit invocations (Only)
Control after how many times a callback should no longer be executed:
// Execute up to 3 times
sut.SetupMock.Method.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Do(() => Console.WriteLine("Up to 3 times")).Only(3);
// Executes the callback only once
sut.SetupMock.Property.TotalDispensed
.Throws(new Exception("This exception is thrown only once")).OnlyOnce();
Repeat invocations (For)
Control how many times a callback should be repeated:
sut.SetupMock.Method.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Do(() => Console.WriteLine("First three times")).For(3)
.Do(() => Console.WriteLine("Next three times")).For(3);
sut.SetupMock.Property.TotalDispensed
.Returns(10).For(1)
.Returns(20).For(2)
.Returns(30).For(3);
// Reads: 10, 20, 20, 30, 30, 30, 10, 20, 20, 30, 30, 30 …
Repeat Forever
If you have a sequence of callbacks, you can mark the last one to repeat indefinitely using .Forever() to avoid
repeating the sequence from start:
sut.SetupMock.Method.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Returns(true).For(2) // Returns true the first two times
.Returns(false).Forever(); // Then always returns false
Parallel callbacks
When you specify multiple callbacks, they are executed sequentially by default. You can change this behavior to always
run specific callbacks in parallel using .InParallel():
sut.SetupMock.Method.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Do(() => { Console.WriteLine("Runs every second iteration"); })
.Do(() => { Console.WriteLine("Runs always in parallel"); }).InParallel()
.Do(() => { Console.WriteLine("Runs every other iteration"); });
Note:
Parallel execution via .InParallel() only applies to callbacks defined via Do, not to other setup callbacks like
Returns or Throws.
Invocation counter
Access the zero-based invocation counter in callbacks:
sut.SetupMock.Method.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Do((count, _, _) => Console.WriteLine($"Call #{count}"));
sut.SetupMock.Property.TotalDispensed.OnGet
.Do((count, value) => Console.WriteLine($"Read #{count}, value: {value}"));