Scenarios
Scenarios let you define multiple sets of setups on a single mock and switch between them at runtime. This is useful
when the collaborator behaves differently depending on its internal state, for example a chocolate dispenser that
starts empty, becomes loaded after Refill(…), and runs out of stock after dispensing. The examples on this page add a Refill method to the IChocolateDispenser and use an OutOfStockException:
public interface IChocolateDispenser
{
// the members from the core concepts, and:
bool Refill(int amount);
}
public class OutOfStockException : Exception;
A mock always has an active scenario (the empty string "" by default). When a member is called, Mockolate looks
for a matching setup in the active scenario first, and then in the default setups.
Defining scenarios
Use InScenario(name) to scope setups to a named scenario. Its Setup property mirrors dispenser.Mock.Setup, but
the setups only apply while the scenario is active:
dispenser.Mock.InScenario("empty").Setup.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Throws<OutOfStockException>();
dispenser.Mock.InScenario("loaded").Setup.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Returns(true);
A callback overload groups multiple setups of the same scenario:
dispenser.Mock.InScenario("loaded", scope =>
{
scope.Setup.Dispense(It.IsAny<string>(), It.IsAny<int>()).Returns(true);
scope.Setup.Refill(It.IsAny<int>()).Returns(true);
});
Switching scenarios
Chain .TransitionTo(name) on any method, property, indexer or event subscription setup to change the active
scenario whenever the setup is used. The transition happens in addition to the return value or exception of the
setup:
dispenser.Mock.InScenario("empty")
.Setup.Refill(It.IsAny<int>())
.Returns(true)
.TransitionTo("loaded");
dispenser.Mock.InScenario("loaded")
.Setup.Dispense(It.IsAny<string>(), It.IsAny<int>())
.Returns(true)
.TransitionTo("empty");
To set the starting state, change the active scenario directly with dispenser.Mock.TransitionTo("empty");.
Resolution rules
When the mock is called, Mockolate looks for a matching setup in this order:
- The setups of the active scenario.
- The default setups (registered via
dispenser.Mock.Setup). - The mock's default behavior.
Scenario setups add to the default setups instead of replacing them: register catch-all setups in the default scope
and override specific members per scenario. Setups registered via InScenario never apply outside their scenario.