Jef*_*eff 3 unit-testing dependency-injection xunit autofixture
考虑以下测试,
[Theory, MyConventions]
public void GetClientExtensionReturnsCorrectValue(BuilderStrategy sut)
{
var expected = ""; // <--??? the value injected into BuilderStrategy
var actual = sut.GetClientExtension();
Assert.Equal(expected, actual);
}
Run Code Online (Sandbox Code Playgroud)
和我正在使用的自定义属性:
public class MyConventionsAttribute : AutoDataAttribute {
public MyConventionsAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization())) {}
}
Run Code Online (Sandbox Code Playgroud)
和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);
}
}
Run Code Online (Sandbox Code Playgroud)
我需要知道在构造函数参数中注入了什么值,clientID
以便我可以使用它来与输出进行比较GetClientExtension
.是否可以在将SUT注入测试方法时仍然编写这种测试方式?
如果您将注入clientID
(以及dependency
同样)的只读属性公开,您始终可以查询它们的值:
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; }
}
}
Run Code Online (Sandbox Code Playgroud)
通过此更改,您现在可以像这样重写测试:
[Theory, MyConventions]
public void GetClientExtensionReturnsCorrectValue(BuilderStrategy sut)
{
var expected = sut.ClientID.Substring(sut.ClientID.LastIndexOf("-") + 1);
var actual = sut.GetClientExtension();
Assert.Equal(expected, actual);
}
Run Code Online (Sandbox Code Playgroud)
有些人不喜欢在单元测试中复制生产代码,但我宁愿争辩说,如果你遵循测试驱动开发,它就是复制测试代码的生产代码.
无论如何,这是一种称为派生值的技术.在我看来,只要它保持1的圈复杂度,我们仍然可以相信这个测试.此外,只要重复的代码只出现在两个地方,三个规则就表明我们应该保持这样.