在MOQ模拟上使用设置时设置变量

时间:2014-08-08 19:08:43

标签: c# unit-testing parameter-passing moq

我有一个代码片段可供模拟,在测试方法中如下所示:

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);
}

如何通过设置参数来模拟mock的行为:

我正在尝试实施以下代码段:

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();
}

应该做什么才能让mock返回由我初始化的数据,而不是该特定方法的原始行为?

1 个答案:

答案 0 :(得分:1)

要模拟LoadAllRules,它需要是virtual,否则您需要模拟界面。设置out值不是问题,我也不认为它提供了原始行为&#39;方法...我认为你没有得到任何值,因为Setup找不到匹配。由于ref参数,它没有找到匹配项。 Moq不支持It.Any上的ref匹配...您必须提供相同的对象实例才能匹配。请参阅下面的示例。它配置ref和不同的out值。该测试使用xUnit.net和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
    }

这是有效的,因为sut.ErrorsMethodToBeTested内使用的对象相同。在您的示例代码中,情况并非如此......有两个不同的对象,因此不会匹配。

将测试添加到旧系统总是有问题的。 Moq今天无法解决这个问题。您可以查看RhinoMocks which appears to be able to handle ref args