When you’re mocking a method that’s called multiple times, you may want to change the behavior of the method each time it’s called.
The way you do this with Moq is by using SetupSequence(), like this:
mock.SetupSequence(t => t.ShouldRetry())
.Returns(true)
.Returns(true)
.Returns(false);
Code language: C# (cs)
Note: You can also make it throw an exception in the sequence.
Example of code I want to test – it processes data in a loop
The DataProcessor class gets data from an external source in a loop. While there is data available, it processes it, converting the data to an ASCII string.
How would you unit test this?
public interface IDataSource
{
bool HasData();
byte[] GetNextDataBlock();
}
public class DataProcessor
{
private readonly IDataSource DataSource;
public DataProcessor(IDataSource dataSource)
{
DataSource = dataSource;
}
public string ProcessData()
{
StringBuilder sb = new StringBuilder();
while(DataSource.HasData())
{
var data = DataSource.GetNextDataBlock();
sb.Append(Encoding.ASCII.GetString(data));
}
return sb.ToString();
}
}
Code language: C# (cs)
Unit test that uses SetupSequence()
You want to prove that DataProcessor is getting all available data and returning it in the expected ASCII format.
To unit test this, you would mock out IDataSource and use SetupSequence() to mock the following behavior:
- HasData() – returns true the first two times it’s called, then returns false.
- GetNextDataBlock() – returns “hello ” the first time it’s called, then it returns “world”.
[TestMethod()]
public void TestProcessData_WhenHasTwoDataBlocks_ReturnsAsciiString()
{
//arrange
var mockDataSource = new Mock<IDataSource>();
mockDataSource.SetupSequence(t => t.HasData())
.Returns(true)
.Returns(true)
.Returns(false);
mockDataSource.SetupSequence(t => t.GetNextDataBlock())
.Returns(ASCIIEncoding.ASCII.GetBytes("hello "))
.Returns(ASCIIEncoding.ASCII.GetBytes("world"));
var dataProcessor = new DataProcessor(mockDataSource.Object);
//act
var data = dataProcessor.ProcessData();
//assert
Assert.AreEqual("hello world", data);
}
Code language: C# (cs)
Thanks, this saved my day, had issue with object disposed next time it was to be used in a using(…) {…}
Awesome, I’m glad this helped!