C# mocking Mock<StreamWriter> - c#

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));
}

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.

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.

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.

Related

Unit test of the second method call

I have a unit test where I am using Moq and Fluent Assertions:
[Fact]
public void GetSymbols_ShouldSetSucceedToTrue_WhenSecondAttemptSucceed()
{
string selectedFileName = "testFileName.txt";
string[] expectedResult = new string[] { "testSymbol1", "testSymbol2" };
Mock<IOpenFileDialogService> mockFileDialogService = new Mock<IOpenFileDialogService>();
mockFileDialogService.SetupSequence(m => m.ShowDialog()).Returns(false).Returns(true);
mockFileDialogService.Setup(m => m.FileName).Returns(selectedFileName);
Mock<IFileService> mockFileService = new Mock<IFileService>();
mockFileService.Setup(m => m.ReadAllLines(selectedFileName)).Returns(expectedResult);
SymbolsProviderFromFile spff = new SymbolsProviderFromFile(mockFileDialogService.Object, mockFileService.Object);
// Act
spff.GetSymbols();
IEnumerable<string> result = spff.GetSymbols();
// Assert
using (new AssertionScope())
{
result.Should().Equal(expectedResult);
spff.Succeed.Should().BeTrue();
}
}
I would like to check the second call of my method.
Unfortunately when I debug this code, the spff.GetSymbols() method is only called once and it is called on the result.Should().Equals(expectedResult) line when the result is checked. There is some kind of a lazy loading here - the method is only called when the result is needed.
Why is it not called immediately in the spff.GetSymbols() line? How can I change this behavior and how can I call testing method twice in unit test?
Problem has been resolved thanks to #Dennis Doomen.
An issue about not executing method immediately was in the implementation of the spff.GetSymbols() method which uses yield return so it wasn't really related to unit testing.

Mocking in Xunit- How to verify method that returns some value

I have created a unit test method that verifies method is called, below is the code for the same.The method builds email object and calls GeneratePDF method which returns bytes further BuildEmailInfo method returns email object.
public class SMTPEmailSender : IEmailSender
{
private IPDFCreater _pdfCreater;
public SMTPEmailSender(IPDFCreater pdfCreater)
{
_pdfCreater = pdfCreater;
}
public Email BuildEmailInfo(string sMTPServerUrl, FaxMailDTO faxAsMailRequest)
{
Email email=null;
try
{
var otp = new PDFData { OTP =faxAsMailRequest.OTP};
email = new Email
{
SMTPServerUrl = sMTPServerUrl,
Encoding = Encoding.UTF8,
ToAddress = faxAsMailRequest.ToEmailAddress,
ToAddressDisplayName = faxAsMailRequest.ToAddressDisplayName,
FromAddress = faxAsMailRequest.FromEmailAddress,
Subject = faxAsMailRequest.Subject,
Body = faxAsMailRequest.Body,
FromAddressDisplayName = faxAsMailRequest.FromAddressDisplayName,
ContentStream = new MemoryStream(_pdfCreater.GeneratePDF(otp)),
AttachmentName = faxAsMailRequest.FaxFileName
};
}
catch(Exception ex)
{
Log.Error("Method : BuildEmailInfo. Exception raised while building email data : {#Message}", ex.Message, ex);
}
return email;
}
Below is my unit test code , whenever I execute this it throws an error Expected invocation on the mock at least once, but was never performed: x=>x.GeneratePDF(pdfdata). Also Let me know if it is right way to perform the test
public class SMTPEmailSenderTest
{
private SMTPEmailSender _sMTPEmailSender;
Mock<IPDFCreater> _mockPdfCreator;
public SMTPEmailSenderTest()
{
_mockPdfCreator = new Mock<IPDFCreater>();
_sMTPEmailSender = new SMTPEmailSender(_mockPdfCreator.Object);
}
[Theory]
[MemberData(nameof(GetFaxAsMailObject))]
public void BuildEmailInfoTest_ReturnsValidEmailObject(FaxMailDTO faxMailDTO)
{
string smpturl = "localhost";
var otp = new PDFData { OTP = faxMailDTO.OTP };
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
}
}
This line:
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
performs a 'verification'. This is an assertion that checks if method .GeneratePDF has been called on _mockPdfCreator with otp as its parameter.
All .Verify methods from the interface of the Mock object are used to check if some method or property were called. You can also provide some filters to see if certain parameters were passed, for example:
_myMock.Verify(x => x.FooBar(5));
_myMock.Verify(x => x.FooBar(123));
_myMock.Verify(x => x.FooBar(It.IsAny<int>());
_myMock.Verify(x => x.FooBar(It.Is<int>(number => (number-5)%3 > 10));
all of these check if FooBar was alled on _myMock, but each of them looks only at calls that used certain values of parameters: 5, 123, anything-that-is-int, or (...).
You cannot use .Verify to check for the return value.
There's no such option there.
Why? Think about it. You've had:
_mockPdfCreator = new Mock<IPDFCreater>();
....
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
The _mockPdfCreator is your mock object. Not a real thing. It's a tiny ghost that acts as if it were some IPDFCreater.
There's not a slightest bit of a real implementation there.
How can you expect that GeneratePDF returns anythin meaningful?
It just won't. Nothing's there behind it. If anything called that method GeneratePDF, it would return NULL (or throw exception, depending on mocking mode: Loose/Strict).
...unless you SET UP your mock to do it differently:
var theThing = ...;
_mockPdfCreator = new Mock<IPDFCreater>();
_mockPdfCreator.Setup(x => x.GeneratePDF(It.IsAny<...>())).Returns(theThing);
....
// ... now check what `GeneratePDF` returned?!
Now of anything calls GeneratePDF method, it will return theThing. Alright.
But you knew that already. There's nothing to check. You set up GeneratePDF to return the thing, so there's not a slightest point to check what GeneratePDF returned. It's your mock and your setup!
Sooo, if anything called GeneratePDF, then NULL would be returned, because there's no setup for GeneratePDF. However, as Verify proved, the GeneratePDF was never called. This means that when you created the SMTPEmailSender giving it the mock as parameter:
_mockPdfCreator = new Mock<IPDFCreater>();
_sMTPEmailSender = new SMTPEmailSender(_mockPdfCreator.Object);
and then in test you've had:
....
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
then, apparently, the _sMTPEmailSender.BuildEmailInfo didn't fancy calling GeneratePDF at all.
Why? No idea. Most probably there was something either in smpturl or faxMailDTO that was considered invalid for this use case and that generate-pdf step was skipped. Check the Result. See if there are any errors or messages that would tell you anything about why it did not even try to call GeneratePDF.
Also note that the verification you wrote were
x => x.GeneratePDF(otp)
That's pretty specific. It has hard-coded reference to otp. So maybe it was called, but with different parameter value?
Try adding:
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
_mockPdfCreator.Verify(x => x.GeneratePDF(It.IsAny<PDFData>())); // <-
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
or something along the lines and see which Verify fails. If the former passes and the latter fails, than everything's mostly fine, it's just not the exact OTP that you expected (maybe _sMTPEmailSender cloned it? etc).
In any chance that the former fails, then it means that GeneratePDF is truly not called even a single time, and then it means you have to learn why BuildEmailInfo with params (smpturl, faxMailDTO) doesn't do what you expect. You've got a try-catch-log there. Maybe some nullreferenceexption? But I doubt it.
You've got there:
[MemberData(nameof(GetFaxAsMailObject))] /// <==== B
public void BuildEmailInfoTest_ReturnsValidEmailObject(FaxMailDTO faxMailDTO) // <--- A
{
...
var otp = new PDFData { OTP = faxMailDTO.OTP }; //<--- C
...
_mockPdfCreator.Verify(x => x.GeneratePDF(otp)); //<---D
So, the faxMailDTO is from GetFaxAsMailObject. The BuildEmailInfo gets it via params and passes part of it to GeneratePDF. Then you assert in Verify that D uses newly-constructed otp from line C. That just can't work. The faxMailDTO from A+B so from GetFaxAsMailObject certainly DOES NOT contain otp from C and certainly will not pass otp object to GeneratePDF. The GeneratePDF will get some other PDFData object that came from faxMailDTO from A+B.
I think I've said enough and covered all issues with your test setup.. You almost have it right. Good luck!
Verifications on mock objects should be your 'last resort' in unit tests. Think about it: is an actual requirement violated if the PDF creator does not call the GeneratePDF method? The user only cares that the PDF was generated.
In this case, you can verify the outcome of the BuildEmailInfo method directly, for example:
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
var expectedBytes = ...; // TODO - get the expected byte[] array from somewhere
Assert.Equal(expectedBytes, result.ContentStream.ToArray());
Additionally, you may be able to write this test without mocking the dependency at all? If the actual PDF creator object can be called to generate a byte[] array in memory, you could just use the real object instead of mocking it.

How does one set a variable in a command using Mediatr with Moq?

I have a simple functional style test for output of a command that I've written using Mediatr's IRequest and IRequestHandler<>
[Fact]
public void TestReturnValuesAsync()
{
// Arrange
var handler = new Mock<IRequestHandler<SyncSubmerchantDataCommand, CommandResult<int>>>();
handler.Setup(x => x.Handle(It.IsAny<SyncSubmerchantDataCommand>(), It.IsAny<CancellationToken>())).ReturnsAsync(new CommandResult<int>(0, ResultStatus.Success, "string"));
// Act
var result = handler.Object.Handle(new SyncSubmerchantDataCommand(), new CancellationToken());
// Assert
result.Result.Data.ShouldBe(0);
result.Result.Status.ShouldBe(ResultStatus.Success);
result.Result.Message.ShouldBe("string");
}
Since this command runs as a background task, I don't want it interrupted. I have a variable, submerchantList, that is of type List<T> which is used in a foreach loop to do work. The work is set in a try-catch because I don't want the command interrupted, as I stated before. I want to test the output of the what is written to my logs (_log.info) if an exception is thrown during this process.
public class CommandNameHandler : IRequestHandler<source, destination> {
// constructors and privates
public async destination Handle(param, token)
{
var submerchantList = db call.ToList();
foreach (var item in submerchantList)
{
try {
//does work
}
catch (Exception e) {
if (item != null)
_log.info($"{e} - {item.Id}");
}
return some out put
}
The problem is that I can't seem to figure out how to set the value of the any variable, such as the submerchantList within the Handle in order to throw the exception for my next test. I'm stumped.
Any help would be greatly appreciated.
SOLUTION:
Here was the solution: Stubbing the database call by injecting an in-memory DbSet. I used this resource learn.microsoft.com/en-us/ef/ef6/fundamentals/testing/… This issue was db call.ToList It looked something like this _db.Table.Include(x => x.Foreign).Where(x => x.Foreign.Field == Enum.Value).ToListAsync() While I was setting up the Mock DbSet, I had to use the string version, not the LINQ-chain version in the unit test. So, that means mockDbset.Setup(x => x.Table.Include("Foreign")).Returns(myCustomDbSet); Hope that helps someone!

RhinoMocks VerifyAllExpectations fails for multiple Expects on stubbed method

Dear RhinoMocks users out there. I am a newbie to RhinoMocks and have a problem wrapping my head around something. I need to test two methods in a class, on of them calls the other multiple times. I already tested the one called multiple times separately, the setup is somewhat complex so the idea for testing the other method was to stub the method that has been tested already. Here is a minimal example:
public class TestedClass
{
public virtual void DoSthOnce(List<int> listParam)
{
foreach (var param in listParam)
DoSthMultipleTimes(param);
}
public virtual void DoSthMultipleTimes(int intParam)
{
Console.WriteLine("param: " + intParam);
}
}
I.e. DoSthMultipleTimes() is already tested. The following test code works and verifies that the DoSthMultipletimes()-Method was called for each element of the list that was provided as parameter to DoSthOnce().
var paramList = Enumerable.Range(1, 10).ToList();
var mock = MockRepository.GeneratePartialMock<TestedClass>();
mock.Stub(m => m.DoSthMultipleTimes(Arg<int>.Is.Anything))
.WhenCalled(mi =>
{
// Only for debug; this method is empty in the actual test code.
Console.WriteLine("Stub called with " + mi.Arguments[0]);
});
mock.DoSthOnce(paramList);
// This will not throw an exception
foreach (var param in paramList)
mock.AssertWasCalled(m => m.DoSthMultipleTimes(param));
The output is as expected:
Stub called with 1
Stub called with 2
Stub called with 3
Stub called with 4
Stub called with 5
Stub called with 6
Stub called with 7
Stub called with 8
Stub called with 9
Stub called with 10
However, the following fails throwing an exception although it should be the same thing as above, at least from my understanding:
var paramList = Enumerable.Range(1, 10).ToList();
var mock = MockRepository.GeneratePartialMock<TestedClass>();
mock.Stub(/*same as above*/).WhenCalled(/*same as above*/);
foreach (var param in paramList)
mock.Expect(m => m.DoSthMultipleTimes(param));
mock.DoSthOnce(paramList);
mock.VerifyAllExpectations();
The console output is identical, but an ExpectationViolationException is thrown by VerifyAllExpectations(). Additional information is:
TestedClass.DoSthMultipleTimes(1); Expected #1, Actual #0.
TestedClass.DoSthMultipleTimes(2); Expected #1, Actual #0.
...
TestedClass.DoSthMultipleTimes(10); Expected #1, Actual #0.
The parameters are correct, but what exactly is the problem here?
I'm guessing because of your stub itself.
This piece of code would register the various expectations that you want:
foreach (var param in paramList)
mock.Expect(m => m.DoSthMultipleTimes(param));
This would set the Expectation that DoSthMultipleTimes(1), DoSthMultipleTimes(2), etc are being called.
However your Mock.Stub code would override / stubbing the implementation itself. This resulted that Rhino would execute this override/method (and not calling the original DoSthMultipleTimes method of the original class). As such, when VerifyAllExpectation being called, none of the method in original class was called.
You could verify the above by removing the following:
mock.Stub(m => m.DoSthMultipleTimes(Arg<int>.Is.Anything))
.WhenCalled(mi =>
{
// Only for debug; this method is empty in the actual test code.
Console.WriteLine("Stub called with " + mi.Arguments[0]);
});
Since you are using PartialMock, if you are not implementing the stub, it would call the original method. And supposedly, it would now successfully pass all the expectation.
(NB: beware when using PartialMock as it would run the original method if not being stubbed (ie: database call, etc)).

rhinomocks setting expectation, unit test always passes

I'm trying to become more familiar with the Rhinomocks framework, and I'm trying to understand the Expect methods of rhinomocks.
Here's a unit test I have written:
[TestMethod]
public void Create_ValidModelData_CreatesNewEventObjectWithGivenSlugId()
{
//Arrange
var eventList = new List<Event>() { new Event() { Slug = "test-user" } };
_stubbedEventRepository.Stub(x => x.GetEvents())
.Return(eventList);
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()))
.Repeat
.Once();
var controller = new EventController(_stubbedEventRepository);
EventViewModel model = new EventViewModel();
//Act
//controller.Create(model); COMMENTED OUT
//Assert
_stubbedEventRepository.VerifyAllExpectations();
}
I thought I understood this code to only pass if the SaveEvent(...) method get's called exactly once. However, with controller.Create(model) commented out, the test still passes. Inside controller.Create(model) is where the SaveEvent() method gets called.
I tried the following:
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()));
But it still passes every time, so what am I doing incorrectly stack overflow? The sources I have looked at online haven't been able to help me. Why is VerifyAllExpectations() yielding a successful unit test?
Thank you!
Here's the body of the controller constructor:
public EventController(IEventRepository eventRepository)
{
_eventRepository = eventRepository;
}
edit:
// member variables
private IEventRepository _stubbedEventRepository;
[TestInitialize]
public void SetupTests()
{
_stubbedEventRepository = MockRepository.GenerateStub<IEventRepository>();
}
If you want to verify the behavior of the code under test, you will use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub.

Categories

Resources