I’ve often thought that NMock is under-documented. The way I’ve started to learn how to use this extremely useful library is through the well-formatted examples that Ian has left around. Practical examples often show you far more than a glossary of terms or a list of available methods.
This week Andy and Drew were wanting to test a method which had both a return value and an out parameter. A quick look through the NMock Quickstart, Tutorial, Advanced or Cheat Sheet pages didn’t show any way of achieving this. Thankfully the Blogosphere came through once again to prove that you can do this with NMock.
Say you have a method in your mockable class called:
public string AddGreeting(string userName)
you could expect to write a Stub declaration such as
Stub.On(mockObject)
.Method(AddGreeting)
.With("World")
.Will(Return.Value("Hello World"));
If your method has an out parameter as well, such as:
public string AddGreeting(string userName, out int characterCount)
then your Stub declaration will need to look like this:
string expectedUserName = "World";
Stub.On(mockObject)
.Method(AddGreeting)
.With(Is.EqualTo(expectedUserName), Is.Out)
.Will(new SetNamedParameterAction(["characterCount", 11), Return.Value("Hello World"));
The Is.Out is setting the expectation that one of the parameters you’re specifying is an Out parameter. The SetNamedParameterAction object is undocumented and has been found using reflection. This is a useful feature which hasn’t been documented. The NMock project appears to being built using continuous integration these days but that obviously doesn’t happen with the project documentation.
[Edited to update code sample to make use of Is.EqualTo() and explicitly declared variables for any non-out parameters in the method call. 18th Feb 2009]
This is tricky!
Yours is the only code that gives me an example of setting up an out parameter but I cannot get it to work.
Could you tell me what is wrong with how I have set up the following. I basically want to test that the out string get a value of 31NAA6602100000.
ICoordinateConverter instance = mocks.NewMock();
Expect.Once.On(instance).Method(“ConvertDDToMGRS”).With(0, 0, SpheroidDatum.SPHEROID_WGS84, MGRSPrecision.MGRSPRECISION_1METRE, Is.Out).Will(new SetNamedParameterAction(“mgrsString”, “31NAA6602100000”));
instance.ConvertDDToMGRS(0D, 0D, SpheroidDatum.SPHEROID_WGS84, MGRSPrecision.MGRSPRECISION_1METRE, out mgrsString);
Cheers
Joseph
I created an example to see what might be going wrong. I’d suggest you create your new mock with:
ICoordinateConverter instance = mocks.NewMock();
as you’ve got a specific interface you want the mock object to.
The reason it could be failing is the other parameters in the With statement may need to be changed from literals to use the Is.EqualTo() function. Give it a go with Is.EqualTo() for any static parameters like your 0,0, SpheroidDatum.SPHEROID_WGS84 etc by assigning these to variables first, and then using them like I did in the following example:
using System;
using NMock2;
using NMock2.Actions;
namespace NMockTest
{
public interface ITest
{
void TestMethod(int first, out int second);
}
class Program
{
static void Main(string[] args)
{
// Create the Mockery and set up the Mock Object
Mockery mocks = new Mockery();
ITest testInstance = mocks.NewMock();
// Set up the expectations
int firstParameter = 0;
Stub.On(testInstance).Method(“TestMethod”).With(Is.EqualTo(firstParameter), Is.Out).Will(new SetNamedParameterAction(“second”, 2));
// Test the method
int outTest;
testInstance.TestMethod(0, out outTest);
// Output the result
Console.WriteLine(outTest);
Console.ReadLine();
}
}
}
In the above example, if I simply did the following:
Stub.On(testInstance).Method(“TestMethod”).With(0, Is.Out).Will(new SetNamedParameterAction(“second”, 2));
you get the following exception:
“unexpected invocation of test.TestMethod(, out)”
Let me know if it works for you,
Cheers!
Just to say that the mock can still be Expect.Once.On rather than Stub.On to make it match it at least once.
Cheers
Thanks, I went back to basics and came up with the following which I can build on
namespace MockTests.OutTests
{
public interface IMockOut
{
void TestMethod(int first, out int second);
}
public class MockOut : IMockOut
{
#region IMockOut Members
public void TestMethod(int first, out int second)
{
second = first * 2;
}
#endregion
}
namespace MockTests.OutTests.Tests
{
[TestFixture]
public class MockOutTests
{
private Mockery mocks;
private IMockOut mockOut;
[SetUp]
public void SetUp()
{
mocks = new Mockery();
mockOut = mocks.NewMock();
}
[Test]
public void SimpleMockOutTest()
{
int firstParameter = 1;
Stub.On(mockOut).Method(“TestMethod”).With(Is.EqualTo(firstParameter), Is.Out).Will(new SetNamedParameterAction(“second”, 2));
// Test the method
int outTest;
mockOut.TestMethod(1, out outTest);
Assert.AreEqual(2, outTest);
}
}
}
cheers
I’m stuck. Trying to build with this syntax and I get:
“The type or namespace name ‘SetNamedParameterAction’ could not be found (are you missing a using directive or an assembly reference?)”
using NMock2;
referencing NMock2.dll built 30-Jan-2008
???????
Any guidance would be much appreciated!
Thanks,
Bob
Bob,
SetNamedParameterAction is located under NMock2.Actions. You can either use ‘new NMock2.Actions.SetNamedParameterAction(…)’ in your code or add a ‘using NMock2.Actions;’ under ‘using NMock2;’.
–Mike
To do this in VB.NET remember that
Isis a keyword so you would need to replaceIs.OutwithNMock2.Is.Out.(Please, no VB.NET comments – the language is my client’s choice and I am just pointing this out in case anyone else has to use VB.NET when trying this)