RhinoMocks VerifyAllExpectations fails for multiple Expects on stubbed method - c#

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)).

Related

How to get relevant error message when method called with unexpected parameter?

In Moq, I want to assert that a method TestMethod is called with a specific parameter. When the test fails, I want to see a useful error message similar to:
TestMethod called with unexpected value X for parameter P where Y expected.
public interface ITestObject
{
void TestMethod(int parameter);
}
Just for sake of illustration, I could achieve this using a handcoded mock as follows:
Assert.AreEqual failed. Expected:<3>. Actual:<2>. TestMethod called with unexpected value for parameter 'actual'.
public class MockTestMethodParameter : ITestObject
{
private readonly int expected;
public MockTestMethodParameter(int expected) { this.expected = expected; }
public void TestMethod(int actual)
{
Assert.AreEqual(actual, expected, $"{nameof(TestMethod)} called with unexpected value for parameter '{nameof(actual)}'.");
}
}
[TestMethod]
public void TestHandcodedMockFailure()
{
var mock = new MockTestMethodParameter(expected: 2);
mock.TestMethod(actual: 3);
}
My problem is, I can't figure out how to do this in Moq. When I set up my Mock and call Verify(), I get the following unexpected and unclear error message, instead of the message I was hoping for:
Expected invocation on the mock at least once, but was never performed: test => test.TestMethod(It.Is(2, GenericEqualityComparer))
Performed invocations:
MockUnitTest1.ITestObject:1 (test):
UnitTest1.ITestObject.TestMethod(3)
[TestMethod]
public void TestMoqFailure()
{
var expected = 2;
var actual = 3;
var mock = new Moq.Mock<ITestObject>(Moq.MockBehavior.Strict);
mock.Setup(test => test.TestMethod(Moq.It.IsAny<int>())).Verifiable();
mock.Object.TestMethod(actual);
mock.Verify(test => test.TestMethod(Moq.It.Is(expected, EqualityComparer<int>.Default)));
}
Granted, the information is there, but I expected something more along the lines of, "TestMethod was invoked, but with incorrect parameters." It confuses me when Moq reports that TestMethod was not invoked because, intuitively, I did invoke the mock. I called TestMethod with It.IsAny(), as declared in the mock setup.
I've tried many different adjustments, but none yielding the desired result:
Custom error message
Setup with Is(3)
Setup with Is(2)
MockBehavior.Loose
Different .NET platforms, Framework 4.6.1, Core 2.1, .NET 6.0
Is this simply the way Moq reports error results for Verify()? I'm new to Moq, and while this behavior is unexpected to me, perhaps it is working as designed.
This appears to be normal behavior for mock frameworks in general. Doing the same thing with Telerik JustMock yields a similar error message:
Occurrence expectation failed. Expected exactly 1 call. Calls so far: 0
[TestMethod]
public void TestJustMockFailure()
{
var expected = 2;
var actual = 3;
var mock = Mock.Create<ITestObject>(Behavior.Strict);
Mock.Arrange(() => mock.TestMethod(Arg.IsAny<int>()));
mock.TestMethod(actual);
Mock.Assert(() => mock.TestMethod(Arg.Is(expected)), Occurs.Once());
}
In summary:
The OP's use case (my use case) is valid, verifying a particular parameter value was passed to a mocked method. However, the error message does not report the parameter mismatch as such. Rather, it reports that the entire mocked method call did not occur. This is by design, and appears to be common among popular mock frameworks.

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.

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

Test if method in ClassA has been called from another method in ClassA

It is possible to test if a method has been called using Moq and dependency injection. However, is it possible to test if one method in a class calls another within the same class?
For example, I want to test that if I log a certain exception, that an information message is logged as well.
The method is:
public void Error(string message, Exception exception, long logId = 0)
{
var int32 = (int)logId;
Info("Id was converted to an int so that it would fit in the log: " + logId, int32);
Error(message, exception, int32);
}
This was my attempt at unit testing it. The test fails, is there any way that it can it be done?
void logging_an_error_with_a_long_id_also_logs_info()
{
var mock = new Mock<ILogger>();
var testedClass = new Logger();
var counter = 0;
testedClass.Error("test" + counter++, new Exception("test" + counter), Int64.MaxValue);
mock.Verify(m => m.Info(It.IsAny<string>(), It.IsAny<int>()));
}
Since the Info and Error methods are in the same class (ClassA), I don't believe I can pass ClassA as a dependency into ClassA. So does it not need tested?
The best you're going to be able to do is to make Info virtual. This will allow you to create a Mock<Logger>, set CallBase = true, and verify that Info was called.
var mock = new Mock<Logger>
{
CallBase = true
};
mock.Object.Error("test" + counter++, new Exception("test" + counter), Int64.MaxValue);
mock.Verify(m => m.Info(It.IsAny<string>(), It.IsAny<int>()));
This way, you're still calling the actual implementation of Error, but you've used Moq to verify the Info method was called.
It feels like you're trying to test the wrong thing. It's not really important that the Info method on your class is called from the Error method, what's important is that the behaviour of the Info method occurs. How it happens is an implementation detail of the class.
If I had a math class with two functions:
public int Mult(int x, int y) {
return x*y;
}
public int Sqr(int x) {
return Mult(x,y);
}
I wouldn't test that calling Sqr called out to the Mult function, I would test Sqr(4)==16. It doesn't matter if that calculation takes place in the Sqr method, or in another method of the class.
Whilst #Andrew's solution is probably what you're after, mocking the class you're testing tends to lead to tightly coupled, brittle tests.
If it's impractical to test the call by observing it's side effects, then it may be a sign that the implementation could use a bit of refactoring.

RhinoMocks mock method without return

I am new to mocking. I need to mock method (it doesn't have return value). I cannot find any examples of how to mock a method. I need to mock ITempDa.Import method.
var stub = MockRepository.GenerateStub<ITempDA>();
stub.Stub(x => x.Import(param1)). ???
public void MockedImport() {
// some processing here
}
ITempDa.Import should be mocked and instead some internal method "MockedImport" should be called.
As #JamesLucas said you don't need to use Return() method(you should use this method only when your method is not void).
In this case you should use the Do() method:
var stub = MockRepository.GenerateStub<ITempDA>();
stub.Stub(x => x.Import(Arg<object>.Is.Anything))
.Do(new Action<object>(o => MockedImport()));
or if MockedImport ths same arguments as Import:
stub.Stub(x => x.Import(Arg<object>.Is.Anything))
.Do(new Action<object>(MockedImport);
You should use WhenCalled method when the method under test called your fake and you want to intercept the execution(execute something + change return value/change arguments/do additional steps and etc...). Another reason to use Do instead of WhenCalled is, your code become more readable.
Usually I do not recommend to use IgnoreArguments method. The reason is quite simple, you test the method behaviour. When something violate the method behaviour then the test should fail. IgnoreArguments easily hide things. However, if the calling parameters aren't important do:
stub.Stub(x => x.Import(null))
.IgnoreArguments()
.Do(new Action<object>(o => MockedImport()));
In this instance you don't need a Return() call as the method is void returning. If you want to intercept the call and perform some logic on the mocked operation then use WhenCalled. In this scenario it's also worht just ignoring the arguments in the Stub and handling everything in the WhenCalled expression. e.g.
var stub = MockRepository.GenerateStub<ITempDA>();
stub.Stub(x => x.Import(null))
.IgnoreArguments()
.WhenCalled(invocation =>
{
var arg = invocation.Arguments[0] as ...;
// etc
});

Categories

Resources