C# 如何在单元测试中为被测系统设置调试?
如何设置调试,以便在测试代码下逐步完成系统? 我有一个测试:C# 如何在单元测试中为被测系统设置调试?,c#,.net,visual-studio,unit-testing,moq,C#,.net,Visual Studio,Unit Testing,Moq,如何设置调试,以便在测试代码下逐步完成系统? 我有一个测试: [Test] public void GetDeviceSettings_is_called() { //Arrange var mockDeviceInteractions = new Mock<IDeviceInteractions>(); mockDeviceInteractions.SetupSet(p => p._settingsFil
[Test]
public void GetDeviceSettings_is_called()
{
//Arrange
var mockDeviceInteractions = new Mock<IDeviceInteractions>();
mockDeviceInteractions.SetupSet(p => p._settingsFileQueue = It.IsAny<string>());
mockDeviceInteractions.Setup(x => x.GetDeviceSettings(It.IsAny<string>(), It.IsAny<string>()));
//Act
mockDeviceInteractions.Object._settingsFileQueue = @"C:\";
mockDeviceInteractions.Object.GetDeviceSettings("123123", "dfgdfg");
//Assert
mockDeviceInteractions.VerifyAll();
}
我做错了什么?为什么它不在断点处停止?您必须模拟被测试类调用的对象,而不是类本身
这里有一个例子。它假设您可以将依赖项注入到类中
想象你正在写一个核控制系统。您希望通过编写单元测试来检查系统是否会在需要时指示反应堆执行紧急停堆
public enum ReactorStatus { Ok, OhDear};
public interface IReactorInteractions {
ReactorStatus ShutDown(bool nicely);
ReactorStatus Status { get; }
}
public interface ICore {
ReactorStatus ShutDown(bool nicely);
ReactorStatus GetStatus();
}
public class ReactorInteractions : IReactorInteractions {
private ICore reactor;
public ReactorInteractions(ICore reactor) {
this.reactor = reactor;
}
public ReactorStatus ShutDown(bool nicely) {
return reactor.ShutDown(nicely);
}
public ReactorStatus Status {
get { return reactor.GetStatus(); }
}
}
因此,您需要测试ReactorInteractions类
为了做到这一点,然后模拟它调用的对象,在本例中是ICore
您不想在实际内核上执行操作。这样做肯定会违反纪律,至少是这样
您应该将ICore
mock的Object
属性作为构造函数参数传递给ReactorInteractions类-此属性不是您应该在测试中访问的属性,它仅被设计为传递给被测试的类-被测试的类作用于此“对象”,允许您使用设置
和验证
:
private Mock<ICore> mockCore;
private IReactorInteractions reactor;
[SetUp]
public void TestSetup() {
mockCore = new Mock<ICore>();
reactor = new ReactorInteractions(mockCore.Object);
}
请注意,我没有在测试设置中使用It.IsAny
。对于刚接触mocking的开发人员来说,这种语法非常混乱(在野外看到:尝试在测试调用中使用It.IsAny
作为参数),我希望Moq作者在文档中强调这一点It.IsAny仅在您完全无法控制参数时使用。
在您的情况下,无需使用它。我有任何-您确切地知道要传递的值:
然后在测试中,检查是否使用了实际值。如果您测试It.IsAny
,请记住,您的代码中处理该值的部分可以替换为随机数生成器,单元测试仍然可以通过
话虽如此,Moq有一个限制,即如果列表中的一个参数未知,必须使用它。IsAny
那么它们都必须使用(我不再使用它了,所以我不知道是否仍然如此,但我似乎记得您可以通过使用回调手动验证参数来解决这个问题)您必须模拟被测试类调用的对象,而不是类本身
这里有一个例子。它假设您可以将依赖项注入到类中
想象你正在写一个核控制系统。您希望通过编写单元测试来检查系统是否会在需要时指示反应堆执行紧急停堆
public enum ReactorStatus { Ok, OhDear};
public interface IReactorInteractions {
ReactorStatus ShutDown(bool nicely);
ReactorStatus Status { get; }
}
public interface ICore {
ReactorStatus ShutDown(bool nicely);
ReactorStatus GetStatus();
}
public class ReactorInteractions : IReactorInteractions {
private ICore reactor;
public ReactorInteractions(ICore reactor) {
this.reactor = reactor;
}
public ReactorStatus ShutDown(bool nicely) {
return reactor.ShutDown(nicely);
}
public ReactorStatus Status {
get { return reactor.GetStatus(); }
}
}
因此,您需要测试ReactorInteractions类
为了做到这一点,然后模拟它调用的对象,在本例中是ICore
您不想在实际内核上执行操作。这样做肯定会违反纪律,至少是这样
您应该将ICore
mock的Object
属性作为构造函数参数传递给ReactorInteractions类-此属性不是您应该在测试中访问的属性,它仅被设计为传递给被测试的类-被测试的类作用于此“对象”,允许您使用设置
和验证
:
private Mock<ICore> mockCore;
private IReactorInteractions reactor;
[SetUp]
public void TestSetup() {
mockCore = new Mock<ICore>();
reactor = new ReactorInteractions(mockCore.Object);
}
请注意,我没有在测试设置中使用It.IsAny
。对于刚接触mocking的开发人员来说,这种语法非常混乱(在野外看到:尝试在测试调用中使用It.IsAny
作为参数),我希望Moq作者在文档中强调这一点It.IsAny仅在您完全无法控制参数时使用。
在您的情况下,无需使用它。我有任何-您确切地知道要传递的值:
然后在测试中,检查是否使用了实际值。如果您测试It.IsAny
,请记住,您的代码中处理该值的部分可以替换为随机数生成器,单元测试仍然可以通过
话虽如此,Moq有一个限制,即如果列表中的一个参数未知,必须使用它。IsAny
那么它们都必须使用(我不再使用它了,所以我不知道是否仍然如此,但我似乎记得您可以通过使用回调手动验证参数来解决这个问题)要回答这个问题
如何设置调试,以便在测试代码下逐步完成系统
在Visual Studio中,调试从Start
按钮运行的系统时,无需执行任何特殊的设置
单元测试实际上只是强调类的公共
API的代码。单元测试和对公共API的实际调用之间的唯一区别在于,您有一些属性
要添加到方法中,并且类中存在mock
依赖项。
该类本身与正常调试时保持不变,但您为它设置了处理不同逻辑的场景,然后您可以验证是否正确发生
要让您的测试运行程序在debug
中运行测试,您必须选择它在debug
中运行,否则大多数运行程序默认在基本release
模式下运行。根据您使用的运行程序的不同,这是以不同的方式完成的,但通常允许您右键单击测试调试,并按照Debu行选择一些内容
const string serial = "123456";
mockDeviceInteractions.Setup(m => m.GetDeviceSettingsForSerialNumber(string serial))
.Returns(new DeviceSettings { Serial = serial };
var settings = classUnderTest.GetDeviceSettingsForSerialNumber(serial);
settings.Serial.Should.Be(serial);
mockDeviceInteractions.Setup(x => x.GetDeviceSettings(It.IsAny<string>(), It.IsAny<string>()));
mockDeviceInteractions.Object.GetDeviceSettings("123123", "dfgdfg");
mockDeviceInteractions.SetupSet(p => p._settingsFileQueue = It.IsAny<string>());
mock.SetupProperty(f => f.Name, "foo");
[Test]
public void GetDeviceSettings_is_called()
{
//Arrange
var mockDeviceInteractions = new Mock<IDeviceInteractions>();
var deviceSettings = new Mock<IDeviceSettings>();
mockDeviceInteractions.Setup(x => x.GetDeviceSettings(@"123123", "dfgdfg"))
.Returns(deviceSettings.Object)
.Verifiable();
//Act
var actual = mockDeviceInteractions.Object.GetDeviceSettingsForSerialNumber(@"123123");
//Assert
Assert.Equal(deviceSettings.Object, actual);
mockDeviceInteractions.Verify();
}