我有一个具有以下签名的扩展方法(在 BuildServerExtensions 类中):
public static IEnumerable<BuildAgent> GetEnabledBuildAgents(
this IBuildServer buildServer,
string teamProjectName)
{
// omitted agrument validation and irrelevant code
var buildAgentSpec = buildServer.CreateBuildAgentSpec(teamProjectName);
}
还有另一个调用第一个方法(在 BuildAgentSelector 类中):
public BuildAgent Select(IBuildServer buildServer, string teamProjectName)
{
// omitted argument validation
IEnumerable<BuildAgent> serverBuildAgents =
buildServer.GetEnabledBuildAgents(teamProjectName);
// omitted - test doesn't get this far
}
我正在尝试使用 MSTest 和 Rhino.Mocks (v3.4) 对其进行测试:
[TestMethod]
public void SelectReturnsNullOnNullBuildAgents()
{
Mocks = new MockRepository();
IBuildServer buildServer = Mocks.CreateMock<IBuildServer>();
BuildAgentSelector buildAgentSelector = new BuildAgentSelector();
using (Mocks.Record())
{
Expect.Call(buildServer.GetEnabledBuildAgents(TeamProjectName)).Return(null);
}
using (Mocks.Playback())
{
BuildAgent buildAgent = buildAgentSelector.Select(buildServer, TeamProjectName);
Assert.IsNull(buildAgent);
}
}
当我运行这个测试时,我得到:
System.InvalidOperationException
:Previous method
IBuildServer.CreateBuildAgentSpec("TeamProjectName");
requires a return value or an exception to throw.
这显然是在调用真正的扩展方法而不是测试实现。我的下一个倾向是尝试:
Expect.Call(BuildServerExtensions.GetEnabledBuildAgents(buildServer, TeamProjectName))
.Return(null);
然后我注意到我对 Rhino.Mocks 拦截它的期望可能是错误的。
问题是:如何消除这种依赖并使 Select 方法可测试?
请注意,扩展方法和 BuildAgentSelector 类在同一个程序集中,我宁愿避免更改它或不得不转向扩展方法之外的其他东西,尽管如果我知道它可以处理这种情况,我会考虑另一个模拟框架。
最佳答案
您的扩展方法实际上写得很好。它是一种无副作用的方法,并且正在扩展一个接口(interface),而不是一个具体的类。你快到了,但你只需要走得更远一点。您正在尝试模拟 .GetEnabledBuildAgents(...) 扩展方法...但这实际上并不是可模拟的(除了 TypeMock Isolator 之外的任何东西,这是目前唯一可以实际模拟静态的东西...但是它相当昂贵.)
您实际上对模拟您的扩展方法在内部调用的 IBuildAgent 方法感兴趣:.CreateBuildAgentSpec(...)。如果您考虑清楚,模拟 CreateBuildAgentSpec 方法将解决您的问题。扩展方法是“纯粹的”,所以真的不需要被 mock 。它没有状态,也没有副作用。它在 IBuildAgent 接口(interface)上调用单个方法……这是引导您了解真正需要模拟的内容的第一条线索。
尝试以下操作:
[TestMethod]
public void SelectReturnsNullOnNullBuildAgents()
{
Mocks = new MockRepository();
IBuildServer buildServer = Mocks.CreateMock<IBuildServer>();
BuildAgent agent = new BuildAgent { ... }; // Create an agent
BuildAgentSelector buildAgentSelector = new BuildAgentSelector();
using (Mocks.Record())
{
Expect.Call(buildServer.CreateBuildAgentSpec(TeamProjectName)).Return(new List<BuildAgent> { agent });
}
using (Mocks.Playback())
{
BuildAgent buildAgent = buildAgentSelector.Select(buildServer, TeamProjectName);
Assert.IsNull(buildAgent);
}
}
通过创建 BuildAgent 实例并在 List
希望这可以帮助。
关于unit-testing - 您如何使依赖于扩展方法的方法可测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/918776/