Skip to main content

Indexers

Set up indexers with argument matchers. Supports initialization, returns/throws sequences, and callbacks.

sut.SetupMock.Indexer(It.IsAny<string>())
.InitializeWith(type => 20)
.OnGet.Do(type => Console.WriteLine($"Stock for {type} was read"));

sut.SetupMock.Indexer(It.Is("Dark"))
.InitializeWith(10)
.OnSet.Do((value, type) => Console.WriteLine($"Set [{type}] to {value}"));

Initialization

You can initialize indexers so they work like normal indexers (setter changes the value, getter returns the last set value):

sut.SetupMock.Indexer(It.IsAny<string>()).InitializeWith(42);

Returns / Throws

Set up indexers with Returns and Throws (supports sequences):

sut.SetupMock.Indexer(It.IsAny<string>())
.Returns(1)
.Returns(2)
.Throws(new Exception("Error"))
.Returns(4);

You can also return a value based on the previous value:

sut.SetupMock.Indexer(It.IsAny<string>())
.Returns(current => current + 10); // Increment by 10 each read

Callbacks

Register callbacks on the setter or getter of the indexer:

sut.SetupMock.Indexer(It.IsAny<string>()).OnGet
.Do(() => Console.WriteLine("Indexer was read!"));
sut.SetupMock.Indexer(It.IsAny<string>()).OnSet
.Do(newValue => Console.WriteLine($"Changed indexer to {newValue}!") );

Callbacks can also receive the indexer parameters and the current value:

// Getter with the current value
sut.SetupMock.Indexer(It.IsAny<string>())
.OnGet.Do((string index, int value) =>
Console.WriteLine($"Read this[{index}] current value: {value}"));

// Setter with the new value
sut.SetupMock.Indexer(It.IsAny<string>())
.OnSet.Do((string index, int newValue) =>
Console.WriteLine($"Set this[{index}] to {newValue}"));

Callbacks also support sequences, similar to Returns and Throws:

sut.SetupMock.Indexer(It.IsAny<string>()).OnGet
.Do(() => Console.WriteLine("Execute on all even read interactions"))
.Do(() => Console.WriteLine("Execute on all odd read interactions"));

Notes:

  • All callbacks support more advanced features like conditional execution, frequency control, parallel execution, and access to the invocation counter. See Advanced callback features for details.
  • You can use the same parameter matching and interaction options as for methods.
  • Use .SkippingBaseClass(…) to override the base class behavior for a specific indexer (only for class mocks).
  • When you specify overlapping setups, the most recently defined setup takes precedence.