Ссылка на структуру эффективно превращает ее в ссылочный тип через процесс, называемый "бокс" .Упаковка структуры может вызвать некоторые незначительные изменения в поведении, которые вы должны прочитать о , прежде чем принимать решение.
Другой вариант - добавить некоторую косвенность между структурой и тестируемым кодом.Один из способов - добавить a, чтобы указать тестовое значение.
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());
}
}
Я не буду утверждать, что любой из этих вариантов довольнои я бы подумал о безопасности перед тем, как поместить этот вид бэкдора в общую библиотеку.Интерфейс обычно предпочтительнее, когда он жизнеспособен.
Подобные вещи работают, хотя, и я думаю, что это может быть справедливым компромиссом, когда вы столкнетесь с недружественным к тестам кодом, который вы не хотите агрессивно использовать.реорганизовать.