kooshka
kooshka

Reputation: 871

How to mock a method with multiple Ref params

I have this method call

SecurityController.GetUserPermissions( _
     HttpContext.Current.User.Identity.Name.ToString, GroupAdmin, GroupTrans)

where GroupAdmin and GroupTrans are array of string and are ByRef parameters.

So basically what it does is, given a username fill in the array of admin rights and the array of allowed transactions.

This is legacy code that I can't change.

here's part of my test:

var moqSecurityController = new Mock<ISecurityController>();
var refParam = new string[1] {"test"};
moqSecurityController
   .Setup(x => x.GetUserPermissions("Bob", ref refParam, ref refParam))
   .Callback((string userName, string[] groupAdmin, string[] groupTrans) =>
                                                 {
                                                    groupAdmin[0] = "Test a";
                                                    groupTrans[0] = "Test b";
                                                 });

at the end I would expect to have "test" in both GroupAdmin and GroupTrans, but I'm getting an error:

Invalid callback. Setup on method with parameters (String,String[]&,String[]&)
cannot invoke callback with parameters (String,String[],String[])

What am I missing? Can anyone please help me mock this?

Thanks

Upvotes: 3

Views: 3217

Answers (2)

fluidguid
fluidguid

Reputation: 1681

I get that your solution works, and understand this is an old post, but here is another simpler version of implementation for people from the future :)

Repository method:

    public T Get<T>(params KeyValuePair<string, object>[] parameters) where T : class
    {
        // do whatever you need to do and return an object of type T;
    }

UnitTest method for business class:

    [TestCategory("UnitTest")]
    [TestMethod]
    public void UnitTest_Business_BusinessClassName_GetMethodName()
    {
        var mockRepositoryName = new Mock<IRepositoryName>(MockBehavior.Strict);
        var businessClassName = new BusinessClassName(mockRepositoryName.Object);
        var inputValue = GetInput();
        var expectedResponse = new ResultModel { Id = 1 };

        #region Moq

        var paramsValue = new KeyValuePair<string, object>("Id", inputValue);

        mockRepositoryName
            .Setup(
                p => p.Get<ResultModel>
                    (
                        It.Is<KeyValuePair<string, object>>(i => CheckInputs(i, paramsValue))
                    )
                )
            .Returns(expectedResponse)
            ;

        #endregion Moq

        ResultModel actual = businessClassName.Get(inputValue);

        #region assertion

        Assert.IsNotNull(actual, "actual");
        Assert.AreEqual(inputValue, actual.Id, "Id");

        #endregion
    }

    private static int GetInput()
    {
        return 1;
    }

    private static bool CheckInputs(KeyValuePair<string, object> source, KeyValuePair<string, object> target)
    {
            if (string.IsNullOrWhiteSpace(source.Value?.ToString()) ||
                string.IsNullOrWhiteSpace(target.Value?.ToString()) ||
                int.Parse(source.Value.ToString()) != int.Parse(target.Value.ToString()))
            {
                return false;
            }
        return true;
    }

You are all set.

Upvotes: 0

kooshka
kooshka

Reputation: 871

After some "hard" work found the solution

var moqSecurityController = new Mock<ISecurityController>();
moqSecurityController
    .Setup(x => x.GetUserPermissions(
           It.IsAny<string>(), ref groupAdmin, ref groupTrans))
    .Returns((string s, string[] a, string[] b) =>
           {
               a[0] = "TestAdmin";
               b[0] = "TestTrans";
               return 0;
           });

the problem was the wrong use of Callback instead of Returns

Upvotes: 4

Related Questions