【问题标题】:Mocking a method with Action<T>使用 Action<T> 模拟方法
【发布时间】:2018-05-29 13:56:29
【问题描述】:

我是单元测试的新手,很高兴知道我是否犯了任何错误或没有朝着正确的方向前进。

情况如下:

我正在尝试测试一个方法 (MethodUnderTest),它调用另一个方法 (MethodWithAction),它以 Action&lt;T&gt; 作为参数。 我想模拟MethodWithAction,但是根据返回值测试逻辑。

结构如下:

interface IInterface
{
    void MethodWithAction(Action<string> action);
}

class MyClass : IInterface
{
    public void MethodWithAction(Action<string> action)
    {
        string sampleString = "Hello there";
        action(sampleString);
    }
}

class ClassUnderTest
{
    public IInterface Obj = new MyClass();
    public string MethodUnderTest()
    {
        string stringToBeTested = string.Empty;

        Obj.MethodWithAction(str =>
        {
            if (str.Contains("."))
                stringToBeTested = string.Empty;
            else
                stringToBeTested = str.Replace(" ", string.Empty);
        });
        return stringToBeTested;
    }
}

我的测试方法是这样的:

[TestMethod]
[DataRow("Hello, World", "Hello,World")]
[DataRow("Hello, World.","")]
[DataRow("Hello", "Hello")]
public void MethodUnderTestReturnsCorrectString(string sampleString, string expected)
{
    var mockObj = new Mock<IInterface>();
    mockObj.Setup(m=>m.MethodWithAction(It.IsAny<Action<string>>))
    .Callback(???);
    ClassUnderTest sut = new ClassUnderTest();
    sut.Obj=mockObj.Object;
    string actual = sut.MethodUnderTest();
    Assert.Equal(expected, actual);
 }

我想知道测试中???的位置是什么,或者这个问题有完全不同的方法吗?

【问题讨论】:

  • 你最好在 CodeReview.StackExchange 上问这个

标签: c# .net unit-testing mocking moq


【解决方案1】:

获取在回调中传递给模拟的动作参数并使用示例字符串调用它。

mockObj
    .Setup(m => m.MethodWithAction(It.IsAny<Action<string>>))
    .Callback((Action<string> action) => action(sampleString));

参考Moq Quickstart 以更好地了解如何使用这个模拟框架。

【讨论】:

    【解决方案2】:

    我的第一个直觉是重构 ClassUnderTestIInterface 以便 IInterface 有一个 get 属性,这样你就可以完全删除 IInterface 实现的依赖,而 MyClass 只需要做一个工作(存储 SampleString ):

    interface IInterface
    {
        string SampleString { get; }
    }
    
    // Fix MyClass
    class MyClass : IInterface
    {
        public string SampleString => "Hello There"
    }
    
    class ClassUnderTest
    {
        public string MethodUnderTest(IInterface someObject)
        {
            string stringToBeTested = string.Empty;
    
            if (someObject.SampleString.Contains("."))
                stringToBeTested = string.Empty;
            else
                stringToBeTested = str.Replace(" ", string.Empty);
    
            return stringToBeTested;
        }
    }
    

    所以我们可以完全删除 Action,代码在测试时更易读和更容易理解。

    只是看待问题的另一种方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-17
      • 2016-09-23
      相关资源
      最近更新 更多