Ilya Gazman
Ilya Gazman

Reputation: 32221

C# mocking Mock<StreamWriter>

I am new to C# mocking, I am trying to read some code and I got one of the tests failing, can you please explain to me what the below source code is trying to test and when will it fail?

Mock<StreamWriter> _streamWriterMock;
string[] expectedLines;
.
.
.
foreach (var line in expectedLines)
{
    _streamWriterMock.Verify(a => a.Write(line), Times.Exactly(1));
}

Upvotes: 2

Views: 6377

Answers (3)

BRAHIM Kamel
BRAHIM Kamel

Reputation: 13765

Verify
You might want to check that the method under test was called, or even how many times that method was called

Just to reproduce the issue try this code

class Program
{
    static void Main(string[] args)
    {
        var _streamWriterMock = new Mock<StreamWriter>("output.txt");
        string[] expectedLines= new []{"test","test"};

        foreach (var expectedLine in expectedLines)
        {
            _streamWriterMock.Object.Write(expectedLine);
        }
        foreach (var line in expectedLines)
        {
           _streamWriterMock.Verify(a=>a.Write(line),Times.Exactly(1));    
        }

    }
}

In fact, if you try to mock your code with the array {"test","test"} you will get an exception
Expected invocation on the mock exactly 1 times, but was 2 times: a => a.Write("test")

But if your array is something like the following

string[] expectedLines= new []{"test","test1"};

Your mock will be executed correctly

So your verify will check if your method is called exactly once for the same input. I think that the code main goal is to omit that you write the same output twice.

Upvotes: 6

Nkosi
Nkosi

Reputation: 247098

Given the mocked StreamWriter

At best the foreach loop being used to verify with the mock that the each string in the expected lines array was called on the mocked stream writer's Write method exactly once during the exercising of the subject under test.

The test will fail if any of the expected lines are written more than once.

Review Moq: Quickstart - Verification

Take the following class as an example of a possible subject that depends on a StreamWriter

public class SubjectUnderTest {
    private StringWriter stringWriter;

    public SubjectUnderTest(StringWriter stringWriter) {
        this.stringWriter = stringWriter;
    }

    public void WriteLines(string[] lines) {
        foreach (var line in lines) {
            this.stringWriter.Write(line);
        }
    }
}

The dependency would be mocked when testing and the functionality of the method under test can be verified in isolation.

For example.

[TestMethod]
public void TestMethod1() {
    //Arrange
    var _streamWriterMock = new Mock<StringWriter>();
    string[] expectedLines = new[] { "line1", "line2" };
    var subject = new SubjectUnderTest(_streamWriterMock.Object);

    //Act
    subject.WriteLines(expectedLines);

    //Assert
    foreach (var line in expectedLines) {
        _streamWriterMock.Verify(a => a.Write(line), Times.Exactly(1));
    }
}

If however, expectedLines had duplicates like { "lineN", "lineN" } Then the above test would fail as the verification is expecting the Write method to be called exactly one time with a given string value.

Upvotes: 0

Connell.O&#39;Donnell
Connell.O&#39;Donnell

Reputation: 3703

The test in your example iterates through all of the strings in your expectedLines array and checks that _streamWriterMock.Write(string value) is called on each of them exactly once. It will fail if Write is not called or is called more than once on any of the strings.

Update

Generally mocked methods must be virtual and depending on your mocking framework, the mock's method may need to be setup before being called so it may not be a valid test at all since StreamWriter is a concrete class and Write is not a virtual method.

Upvotes: 0

Related Questions