3

MOQ supports setups for out parameters - no problem. I'd like to be able to set the parameter based on what's passed in the invocation, via Returns() or Callback(). My use case involves mocking out a method with an out parameter.

Here is what I am using to experiment, so far with negative results each time:

public interface ITestClass
{
    string method(string inString, out string outString);
}

public class TestClass : ITestClass
{
    public string method(string inString, out string outString)
    {
        outString = inString + " was passed in";
        return (inString + " was returned");
    }
}

[TestFixture]
public class OutTest
{
    [Test]
    public void Test()
    {
        //Arrange
        Mock<ITestClass> mock = new Mock<ITestClass>(MockBehavior.Strict);
        string stringParm = "value that will be assigned to out parameter";
        mock.Setup(t => t.method(It.IsAny<string>(), out stringParm))
            .Returns((string i, string o) =>
            {
                return i + " was returned"; // o = stringParm already
            })
            .Callback((string s, string oo) =>
            {
                stringParm = s + " was passed in"; // oo = stringParm already
            });
        TestClass real = new TestClass();
        string testString = DateTime.Now.ToLongTimeString();

        //Act
        string realOut;
        string mockOut;
        string realResult = real.method(testString, out realOut);
        string mockResult = mock.Object.method(testString, out mockOut);

        //Assert
        realResult.Should().Be(mockResult); // passes
        realOut.Should().Be(mockOut); // fails - mockout = original stringParm
    }
}
mike mckechnie
  • 844
  • 8
  • 14
  • I see this was implemented outside of the MOQ base in 2009... but it's not available as part of MOQ yet. https://code.google.com/p/moq/issues/detail?id=176 – mike mckechnie Oct 09 '15 at 14:44
  • possible duplicate of http://stackoverflow.com/questions/1068095/assigning-out-ref-parameters-in-moq ? – Fabio Salvalai Oct 12 '15 at 09:25
  • @FabioSalvalai no, that question was about how to assign a value to an out or ref - which I agree MOQ can handle just fine. The stringParm variable in my example works this way. What I want to do is set the value of the out parameter from within the Callback or Return block - so that its value can be affected by the other passed parameters. – mike mckechnie Oct 12 '15 at 09:50
  • okay, got it. I'll post a workaround as a proposed answer. – Fabio Salvalai Oct 12 '15 at 10:12

2 Answers2

0

I know it isn't ideal, but why not passing the resulting expected mockOut instead of "value that will be assigned to out parameter" ?

with

string stringParm = "foo was passed in"
Fabio Salvalai
  • 2,479
  • 17
  • 30
  • I suspect I don't understand your proposal - would you mind showing the line of code that would change in the example I posted up top? – mike mckechnie Oct 12 '15 at 14:11
  • well, I believe I did. replace `string stringParm = "value that will be assigned to out parameter";` with `string stringParm = "foo was passed in"` It will work, only because you only make a call by passing `foo` during your test and no other value than `foo`. – Fabio Salvalai Oct 12 '15 at 14:15
  • Yes - whatever value you set stringParm to, this value will be passed into the out parameter when the method is called. That's why I chose the value I did for stringParm ;) - it describes what happens. What I cannot do is set the out parameter based on what is passed into the method... Which would have to be done from the context of the executing Returns() or Callback()... I've edited the test to emphasize this - the test string now changes on every execution. I want to find a way to make the test pass. – mike mckechnie Oct 13 '15 at 18:30
  • I understand, but you don't need to replicate the logic of the _Subject Under Test_ with your mocked logic. you don't need and you should not. Instead, you should tailor a custom-made _Arrange_ that will respond correctly to your _Act_. – Fabio Salvalai Oct 13 '15 at 18:36
  • Agree completely - that's what I do, normally. In this specific case I'm trying to test a contract though - I need to mock behaviour, within a limited range of possibilities. I've worked around it - but I'd still like to have the ability to do it. I've confirmed fyi that Rhino has support for this, so I could always use that if needed. – mike mckechnie Oct 13 '15 at 19:00
  • I don't really understand what you mean with _I'm trying to test a contract though_, but one thing is for sure, calling a method on a `mock.Object.xxxx()` is usually a bad idea. perhaps you want to review the approach. Now, you can probably do it with RhinoMocks, I'm nor saying you can't. It just looks like it is not necessarily a good practice to take that approach. Basically, you' re comparing the logic of your SUT and the logic of a mocked method. why not compare it with a hardcoded value instead ? – Fabio Salvalai Oct 13 '15 at 19:06
  • Er, the _purpose_ of mocks is to be called, to allow us to sense the parameters passed to them, and to allow them to exhibit some of the behaviour of the object they replace. If you mean that calling code from _within_ a mock is to be avoided, then I agree. Contract testing is a test of behaviour across invocations. It's a way to confirm integration suitability without the expense and inefficiency of integration testing. JB Rainsberger has written a fair bit about it, if you are curious. – mike mckechnie Oct 15 '15 at 06:32
  • I just realized - you may be speaking about the code sample I posted. That code sample is for the stackoverflow question - it's not from my application. I think tests are a far better description of questions than English text can be - if the test passes, the question is answered :) – mike mckechnie Oct 15 '15 at 06:35
0

I recently had to update the solution I use in order to execute callbacks on setups with out parameters.

namespace SupRep.TestUtilities
{
    using System.Reflection;
    using Moq.Language;
    using Moq.Language.Flow;

    public static class MoqExtensions
    {
        public delegate void OutAction<TOut>(out TOut outVal);
        public delegate void OutAction<in T1,TOut>(T1 arg1, out TOut outVal);
        public delegate void OutAction<in T1,in T2,TOut>(T1 arg1, T2 arg2, out TOut outVal);

        public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, TOut>(this ICallback<TMock, TReturn> mock, OutAction<TOut> action)
            where TMock : class
        {
            return OutCallbackInternal(mock, action);
        }

        public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, T1, TOut>(this ICallback<TMock, TReturn> mock, OutAction<T1, TOut> action)
            where TMock : class
        {
            return OutCallbackInternal(mock, action);
        }

        public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, T1, T2, TOut>(this ICallback<TMock, TReturn> mock, OutAction<T1, T2, TOut> action)
            where TMock : class
        {
            return OutCallbackInternal(mock, action);
        }

        private static IReturnsThrows<TMock, TReturn> OutCallbackInternal<TMock, TReturn>(ICallback<TMock, TReturn> mock, object action)
            where TMock : class
        {
            var methodCall = mock.GetType().GetProperty("Setup").GetValue(mock);
            mock.GetType().Assembly.GetType("Moq.MethodCall")
                .InvokeMember("SetCallbackResponse", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, methodCall,
                    new[] { action });
            return mock as IReturnsThrows<TMock, TReturn>;
        }
    }}
mike mckechnie
  • 844
  • 8
  • 14