c# - 有哪些方法可以模拟结构以在单元测试中获取类?
问题描述
我有一门课,我正试图进行单元测试。该类将结构公开为公共属性。该结构还具有一些公共方法(比结构中的方法做得更多)。我无法对结构进行更改(我不拥有该代码,目前风险太大)。
模拟不适用于值类型。有没有办法有效地“模拟结构”?
public class SystemUnderTest
{
public FragileStructCantChange myStruct {get; set;}
public string MethodUnderTest()
{
if(myStruct.LongRunningMethod() == "successful")
return "Ok";
else
return "Fail";
}
}
public struct FragileStructCantChange
{
public string LongRunningMethod()
{
var resultString = DoStuff(); //calls other subsystems
return resultString;
}
}
解决方案
通过接口引用结构有效地将其转换为引用类型,通过一个称为“装箱”的过程。对结构进行装箱可能会导致行为发生一些细微的变化,您应该在做出决定之前阅读这些内容。
另一种选择是在结构和被测代码之间添加一些间接性。一种方法是添加一个来指定测试值。
public class SystemUnderTest
{
public FragileStructCantChange myStruct { get; set; }
// This value can be overridden for testing purposes
public string LongRunningMethodOverride { get; set; }
public string MethodUnderTest()
{
// Call the indirect Func instead of referencing the struct directly
if (LongRunningMethod() == "successful")
return "Ok";
else
return "Fail";
}
private string LongRunningMethod()
=> LongRunningMethodOverride ?? myStruct.LongRunningMethod();
}
public class Tests
{
[Fact]
public void TestingSideDoor()
{
var sut = new SystemUnderTest();
// Override the func to supply any test data you want
sut.LongRunningMethodOverride = "successful";
Assert.Equal("Ok", sut.MethodUnderTest());
}
}
另一种方法是公开一个可覆盖的函数指针......
public class SystemUnderTest
{
public FragileStructCantChange myStruct { get; set; }
// This Func can be overridden for testing purposes
public Func<string> LongRunningMethod;
public SystemUnderTest() {
LongRunningMethod = () => myStruct.LongRunningMethod();
}
public string MethodUnderTest()
{
// Call the indirect Func instead of referencing the struct directly
if (LongRunningMethod() == "successful")
return "Ok";
else
return "Fail";
}
}
public class Tests
{
[Fact]
public void TestingSideDoor()
{
var sut = new SystemUnderTest();
// Override the func to supply any test data you want
sut.LongRunningMethod = () => "successful";
Assert.Equal("Ok", sut.MethodUnderTest());
}
}
另一种选择是使用虚拟方法,它可以由子类或模拟框架(在本例中为Moq)伪造......
public class SystemUnderTest
{
public FragileStructCantChange myStruct { get; set; }
// This method can be overridden for testing purposes
public virtual string LongRunningMethod()
=> myStruct.LongRunningMethod();
public string MethodUnderTest()
{
// Call the indirect method instead of referencing the struct directly
if (LongRunningMethod() == "successful")
return "Ok";
else
return "Fail";
}
}
public class Tests
{
[Fact]
public void TestingSideDoor()
{
var sut = new Mock<SystemUnderTest>();
// Override the method to supply any test data you want
sut.Setup(m => m.LongRunningMethod())
.Returns("successful");
Assert.Equal("Ok", sut.Object.MethodUnderTest());
}
}
我不会声称这些选项中的任何一个都很漂亮,并且在将这种后门放入共享库之前,我会认真考虑安全性。当可行时,接口通常是可取的。
不过,这种事情是可行的,而且我认为当您面对不想侵入性重构的对测试不友好的代码时,这可能是一个公平的妥协。
推荐阅读
- r - 在 R 中,检查 1 是否出现在一行中(在任何选定的列中)
- excel - 适用于 Office 的 Visual Studio 工具(Excel 2016 工作簿)设计器显示蓝屏
- sorting - Haskell 简单的初学者排序程序
- java - 关闭钩子不终止主线程
- javascript - 仅从 SubmitDate 获取日期
- go - 打开新的控制台窗口
- asp.net-mvc - 从列表中提交特定值
- java - 微服务应用程序的 Kubernetes 架构 - 建议
- node.js - 尝试将 Microsoft QnA 制造商服务与 Bot Framework 连接,但未从我的机器人那里得到任何回复
- php - PHP 关联数组联合值