我刚开始为一个新项目写一些测试,遇到了以下“问题”:
我嘲笑依赖
INotifyVariableChangedService
和OpcClient
来测试我的OpcService
:
private readonly OpcUaClient _client;
private readonly INotifyVariableChangedService _notifyVariableChangedService;
private readonly ushort _symbolicsIndex;
public OpcService(INotifyVariableChangedService notifyVariableChangedService)
{
this._notifyVariableChangedService = notifyVariableChangedService;
this._client = new OpcUaClient("", "");
_symbolicsIndex = _client.GetSymbolicsNameSpaceId();
}
在这里你可以看到,我得到了
_symbolicsIndex
,我只需要做一次。因此,我将它坚持在一个领域并在我再次需要它时重复使用它。
这在测试这种方法时出现了一个问题,因为它取决于该字段中的值:
public async Task<KeyValuePair<string, object>> GetVariableValue(string nodeIdentifier, string variableName)
{
var variableValue = await this._client.GetValue(nodeIdentifier, variableName, _symbolicsIndex);
return new KeyValuePair<string, object>(variableName, variableValue.Value);
}
当然我可以重构它并在我的控制器中每次都获得
_symbolicsIndex
,但这似乎根本不是一个干净的解决方案。
有没有办法“模拟”这个领域?我什至应该这样做还是应该重构它并公开一个方法,该方法显式地在我的服务中设置
_symbolicsIndex
,而不是在构造函数中设置它?
任何帮助将不胜感激。
我不认为你可以在不使用反射的情况下模拟私有字段,但我建议你也注入客户端而不是在构造函数中实例化它。
你说客户端已经是一个模拟对象,所以你可以伪造
GetSymbolicsNameSpaceId()
方法并返回所需的模拟值,然后在将客户端传递给构造函数时将其设置为私有字段。
这可能看起来像这样(假设 FakeItEasy 作为模拟库)
private readonly OpcUaClient _client;
private readonly INotifyVariableChangedService _notifyVariableChangedService;
private readonly ushort _symbolicsIndex;
public OpcService(INotifyVariableChangedService notifyVariableChangedService, OpcUaClient client)
{
this._notifyVariableChangedService = notifyVariableChangedService;
this._client = client;
_symbolicsIndex = _client.GetSymbolicsNameSpaceId();
}
测试:
_notifyVariableChangedService = A.Fake<INotifyVariableChangedService>();
_client = A.Fake<OpcUaClient>();
A.CallTo(() => _client.GetSymbolicsNameSpaceId()).Returns(1);
_testee = new OpcService(_notifyVariableChangedService, _client);