C# Moq:如何模拟特性和副作用?
这是一个测试场景 当孩子超过3岁时,C# Moq:如何模拟特性和副作用?,c#,unit-testing,testing,mocking,moq,C#,Unit Testing,Testing,Mocking,Moq,这是一个测试场景 当孩子超过3岁时,IsAdult==true 我要用最小起订量测试。但是失败,因为Age总是根据设置返回2 我如何测试这个?嘲笑是个坏主意吗 不打算使用调试方法或暴力 public class Kid { public virtual float Age { get; private set; } = 0; public bool IsAdult { get; private set; } private float _ageIncreasePerHou
IsAdult==true
我要用最小起订量测试。但是失败,因为Age
总是根据设置返回2
我如何测试这个?嘲笑是个坏主意吗
不打算使用调试方法或暴力
public class Kid
{
public virtual float Age { get; private set; } = 0;
public bool IsAdult { get; private set; }
private float _ageIncreasePerHour = 1;
public void OnHourPass()
{
Age += _ageIncreasePerHour;
if (Age >= 3)
{
IsAdult = true;
}
}
public void Debug_SetAge(float newAge)
{
Age = newAge;
}
}
public class Test_Kid
{
//fail. how can i mocking?
[Test]
public void WhenAgeOver3_Kid_IsAdult_UseMocking()
{
var mockKid = new Mock<Kid> { CallBase = true };
mockKid.Setup(x => x.Age).Returns(2);
Assert.AreEqual(2, mockKid.Object.Age);
mockKid.Object.OnHourPass();
Assert.AreEqual(3, mockKid.Object.Age); // but 2.
Assert.AreEqual(true, mockKid.Object.IsAdult); // but false.
}
//success. but not intended. Debug-Method is anti pattern!
[Test]
public void WhenAgeOver3_Kid_IsAdult_UseDebugMethod()
{
var newKid = new Kid();
newKid.Debug_SetAge(2);
newKid.OnHourPass();
Assert.AreEqual(true, newKid.IsAdult);
}
}
公共类儿童
{
公共虚拟浮点年龄{get;private set;}=0;
公共布尔IsAdult{get;私有集;}
私人浮动_ageIncreasePerHour=1;
在HourPass()上的公共void
{
年龄+=\u年龄每小时增加一次;
如果(年龄>=3)
{
IsAdult=true;
}
}
公共无效调试设置(浮动新设置)
{
年龄=新年龄;
}
}
公开班级考试
{
//失败。我怎么能嘲笑你呢?
[测试]
当管理者3(你的孩子)是成年人(你使用嘲弄)时公共无效
{
var mockKid=newmock{CallBase=true};
mockKid.Setup(x=>x.Age).Returns(2);
AreEqual(2,mockKid.Object.Age);
mockKid.Object.OnHourPass();
Assert.AreEqual(3,mockKid.Object.Age);//但是2。
Assert.AreEqual(true,mockKid.Object.IsAdult);//但是false。
}
//成功。但不是有意的。调试方法是反模式的!
[测试]
当管理者3_Kid_IsAdult_UseDebugMethod()时公共无效
{
var newKid=newKid();
newKid.Debug_设置(2);
newKid.OnHourPass();
断言.AreEqual(对,newKid.IsAdult);
}
}
Moq无法与年龄
属性的私有setter一起工作,因此在使用Moq时会遇到困难,因为如果您试图设置属性的setter来记录行为(副作用),它将引发异常
但是,您可以避免完全使用Moq,并将值设置为测试主题的包装器
使用PrivateObject.SetProperty
可以设置测试的初始值,然后根据需要执行测试
假定
public class Kid {
public virtual float Age { get; private set; }
public bool IsAdult { get; private set; }
private float _ageIncreasePerHour = 1;
public void OnHourPass() {
Age += _ageIncreasePerHour;
if (Age >= 3) {
IsAdult = true;
}
}
}
测试看起来是这样的
public void _WhenAgeOver3_Kid_IsAdult() {
//Arrange
var initialAge = 2;
var expectedAge = initialAge + 1;
var kid = new Kid();
var wrapper = new PrivateObject(kid);
wrapper.SetProperty("Age", initialAge);
Assert.AreEqual(initialAge, kid.Age);
//Act
kid.OnHourPass();
//Assert
Assert.AreEqual(expectedAge, kid.Age); // should be 3.
Assert.AreEqual(true, kid.IsAdult); // should be true.
}
如果您能够更改主题,另一个选项是重构主题,在其构造函数中使用可选参数来设置初始Age
public class Kid {
public Kid(int initialAge = 0) {
Age = initialAge;
}
public virtual float Age { get; private set; }
public bool IsAdult { get; private set; }
private float _ageIncreasePerHour = 1;
public void OnHourPass() {
Age += _ageIncreasePerHour;
if (Age >= 3) {
IsAdult = true;
}
}
}
这将允许对测试进行重构,以及
public void _WhenAgeOver3_Kid_IsAdult() {
//Arrange
var initialAge = 2;
var expectedAge = initialAge + 1;
var kid = new Kid(initialAge);
Assert.AreEqual(initialAge, kid.Age);
//Act
kid.OnHourPass();
//Assert
Assert.AreEqual(expectedAge, kid.Age); // should be 3.
Assert.AreEqual(true, kid.IsAdult); // should be true.
}
你为什么要嘲笑我?你不能创建一个实例,调用
OnHourPass()
直到年龄超过3岁,然后断言isadalt
?这只是一个例子。在我的代码中,被测试类有许多依赖项。我同意你的想法,(直到年龄满足条件为止),但在一些更复杂的情况下,可能会很困难。。。