Deepak Kataria
Deepak Kataria

Reputation: 89

Setting out variable while using setup on a MOQ mock

I have a code snippet to mock which is as follows inside a test method:

IManager imanager;

public classToBeTested(Manager manager)
{
  imanager=manager;
}

public void methodToBeTested()
{
  StringBuilder errorString = new StringBuilder();
  List<RuleWrapper> allRules;
  Dictionary<Guid, RuleConfiguration> allRuleConfigurations;
  imanager.LoadAllRules(ref errorString, out allRuleConfigurations, out allRules);
  SetGlobalRuleConfigurations(settingsManager, allRuleConfigurations, _globalRuleConfigurations);
}

How do I mock the behavior of mock by setting up out parameters:

I have the following snippet that I am trying to implement:

public void methodUsedForTesting()
{
  StringBuilder errorString = new StringBuilder();
  List<Rule> allRules = new List<Rule>();
  Dictionary<Guid, RuleConfiguration> allRuleConfigurations = new Dictionary<Guid,RuleConfiguration>();

  //Code for Initializing above Data members
  RuleConfiguration ruleConfiguration1 = new RuleConfiguration("First");
  RuleConfiguration ruleConfiguration2 = new RuleConfiguration("Second");
  allRuleConfigurations.Add(ruleConfiguration1);
  allRuleConfigurations.Add(ruleConfiguration2);

  Rule rule1 = new Rule("First");
  Rule rule2 = new Rule("Second");
  allRules.add(rule1);
  allRules.add(rule2);


  Mock<Manager> mockManager = new Mock<Manager>();
  mockManager.Setup(p => p.LoadAllRules(ref errorString, out allRuleConfigurations, out allRules));


  classToBeTested classtest = new classToBeTested(mockManager.Object);
  classtest.methodToBeTested();
}

What should be done so that the mock returns the data initialized by me and not the original behavior of that particular method?

Upvotes: 1

Views: 3358

Answers (1)

jltrem
jltrem

Reputation: 12524

To mock LoadAllRules it will need to be virtual or you need to be mocking an interface. Setting up your out values is not the problem, and I don't think it is providing the 'original behavior' of the method ... I think you are just not getting any values because the Setup is not finding a match. It isn't finding a match because of the ref parameter. Moq doesn't support an It.Any match on ref ... you have to provide the same object instance in order to match. See my example below. It configures the ref and different out values. The test is using xUnit.net with Moq.

    public interface IFoo
    {
        void Bar(ref StringBuilder err, out string val1, out string val2);
    }

    public class Foo : IFoo
    {
        public void Bar(ref StringBuilder err, out string val1, out string val2)
        {
            val1 = "Hello";
            val2 = "Howdy";
        }
    }

    public class ClassToBeTested
    {
        private IFoo _foo;

        public StringBuilder Errors = new StringBuilder();

        public ClassToBeTested(IFoo foo)
        {
            _foo = foo;
        }

        public string MethodToBeTested()
        {
            string val1, val2;
            _foo.Bar(ref Errors, out val1, out val2);
            return val1 + " " + val2;
        }
    }

    [Fact]
    public void MethodUsedForTesting()
    {
        var foo = new Mock<IFoo>();
        var sut = new ClassToBeTested(foo.Object);

        var val1 = "Hi";
        var val2 = "Hey";

        // the setup for a ref has to be the same object instance 
        // that is used by MethodToBeTested() ...
        // there isn't currently It.Any support for ref parameters
        foo.Setup(x => x.Bar(ref sut.Errors, out val1, out val2));

        string expected = "Hi Hey";
        string actual = sut.MethodToBeTested();

        Assert.Equal(expected, actual); // this test passes
    }

This works because the sut.Errors is the same object as is used inside of MethodToBeTested. In your sample code this is not the case ... there are two different objects so there will not be a match.

Adding tests to a legacy system is always problematic. Moq can't handle this today. You might take a look at RhinoMocks which appears to be able to handle ref args.

Upvotes: 1

Related Questions