3

考虑以下测试,

[Theory, MyConventions]
public void GetClientExtensionReturnsCorrectValue(BuilderStrategy sut)
{
    var expected = ""; // <--??? the value injected into BuilderStrategy
    var actual = sut.GetClientExtension();
    Assert.Equal(expected, actual);
}

和我正在使用的自定义属性:

public class MyConventionsAttribute : AutoDataAttribute {
    public MyConventionsAttribute()
        : base(new Fixture().Customize(new AutoMoqCustomization())) {}
}

和 SUT:

class BuilderStrategy {
    private readonly string _clientID;
    private readonly IDependency _dependency;
    public void BuilderStrategy(string clientID, IDependency dependency) {
        _clientID = clientID;
        _dependency = dependency;      
    }
    public string GetClientExtension() {
        return _clientID.Substring(_clientID.LastIndexOf("-") + 1);
    }
}

我需要知道什么值被注入到构造函数参数clientID中,以便我可以使用它与GetClientExtension. 是否可以在编写将 SUT 注入测试方法的这种测试风格的同时执行此操作?

4

1 回答 1

6

如果您将注入的clientIDdependency以及)公开为只读属性,则始终可以查询它们的值:

public class BuilderStrategy {
    private readonly string _clientID;
    private readonly IDependency _dependency;
    public void BuilderStrategy(string clientID, IDependency dependency) {
        _clientID = clientID;
        _dependency = dependency;      
    }
    public string GetClientExtension() {
        return _clientID.Substring(_clientID.LastIndexOf("-") + 1);
    }

    public string ClientID
    {
        get { return _clientID; }
    }

    public IDependency Dependency
    {
        get { return _dependency; }
    }
}

不会破坏封装,而是称为 Structural Inspection

通过此更改,您现在可以像这样重写测试:

[Theory, MyConventions]
public void GetClientExtensionReturnsCorrectValue(BuilderStrategy sut)
{
    var expected = sut.ClientID.Substring(sut.ClientID.LastIndexOf("-") + 1);
    var actual = sut.GetClientExtension();
    Assert.Equal(expected, actual);
}

有些人不喜欢在单元测试中复制生产代码,但我宁愿争辩说,如果您遵循测试驱动开发,那么复制测试代码的是生产代码。

无论如何,这是一种称为派生值的技术。在我看来,只要它的圈复杂度为 1,我们仍然可以信任 test。此外,只要重复的代码只出现在两个地方,三法则建议我们应该保持这样。

于 2013-08-14T17:55:48.663 回答