使用Action <t>

时间:2018-05-29 13:56:29

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

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

情况如下:

我正在尝试测试一个方法(MethodUnderTest),该方法调用另一个以MethodWithAction为参数的方法(Action<T>)。 我想模拟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);
 }

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

2 个答案:

答案 0 :(得分:2)

获取在回调中传递给mock的action参数,并使用示例字符串调用它。

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

参考Moq Quickstart以更好地理解如何使用此模拟框架。

答案 1 :(得分:0)

我的第一直觉是重构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,并且在测试时代码更易读,更容易理解。

另一种看待问题的方式。