How to test method with 'out' parameter(s)?
Asked Answered
S

1

6

I am trying to write a unit test for a method that has out parameters. My method specifically is a TryParse method for my custom object. I am using .NET 4.5/5 with Visual Studio 2013. This allows me to fully realize private/internal and static objects using the PrivateType object. The one thing that seems to escape me is how to test for the out parameter as I cannot use this keyword in the InvokeStatic method. I am looking for the proper solution to test this architecture design.

The use for TryParse is part of a TypeConverter process as outlined in the WebAPI Parameter Binding post By Mike Wilson

public class MyFilter
{
    public string Field { get; set; }
    //... removed for brevity

    internal static bool TryParse(string sourceValue, out MyFilter filter)
    {
        //... removed for brevity
    }
}

public class MyFilterTests
{
    [TestMethod]
    [TestCategory("TryParse")]
    public void TryParseWithTitleOnly()
    {
        var stringSource = "{field:'DATE.FIELD'}";

        MyFilter tryParseOut = null;

        var target = new PrivateType(typeof(MyFilter));

        var tryParseReturn = target.InvokeStatic("TryParse", stringSource, tryParseOut);

        var expectedOut = new MyFilter()
        {
            Field = "DATE.FIELD"
        };

        Assert.IsTrue((bool)tryParseReturn);
        Assert.AreEqual(expectedOut, tryParseOut);
    }
}
Sulfapyrazine answered 10/3, 2015 at 17:27 Comment(2)
And TryParse has to be internal?Heterogeneous
Since the architectural design is to limit access to properties not needed externally (separation of concern). This forces our developers to utilize the proper coding patterns when working with the data objects.Sulfapyrazine
U
12

Personally, I'd use InternalsVisibleTo in order to make the method visible to your test code, but if you do want to use PrivateType, I'd expect you to be able to just create an object[] which you keep a reference to, pass it into InvokeStatic, and then get the value out again:

object[] args = new object[] { stringSource, null };
var tryParseReturn = target.InvokeStatic("TryParse", args);

...

// args[1] will have the value assigned to the out parameter
Assert.AreEqual(expectedOut, args[1]);

At least, I'd expect that to work - that's how reflection generally handles ref and out parameters.

Uncleanly answered 10/3, 2015 at 17:35 Comment(5)
args isn't passed to InvokeStatic or I'm missing something?Caddaric
@Caddaric InvokeStatic has several interfaces, the one I am attempting to use in this scenario is documented here. msdn.microsoft.com/en-us/library/ms244026.aspxSulfapyrazine
@JonSkeet thanks, this is actually what I should have been doing. I got all wrapped up in testing all my other static processes this way, that I forgot that I can do this for 'internal' processes to make 'friend's with other assemblies.Sulfapyrazine
The proposed solution by @JonSkeetCaddaric
@Caddaric Yes Jon Skeet's solution works. I don't have a IComparer<MyFilterComparer> so I have to explicitly evaluate my Assert.IsEqual(expected, actual), but otherwise the test is working now.Sulfapyrazine

© 2022 - 2024 — McMap. All rights reserved.