Moq 不订阅构造函数中的事件
Moq does not subscribe to events in constructor
我在单元测试 (xUnit) 中使用 Moq(4.2.1502.911)。在构造函数中,被构造的对象试图订阅依赖事件(参数),但它似乎不起作用。
下面的代码是模拟问题的例子。 Alarm class 使用 ICam 接口依赖性在有物体移动时发出警报。
public interface ICam
{
event EventHandler VisualDetected;
}
public class Alarm : ICam
{
private ICam _cam;
public Alarm(ICam cam)
{
_cam = cam;
// Subscribe to forward events, DOES NOT WORK
_cam.VisualDetected += VisualDetected;
}
public event EventHandler VisualDetected;
// If I call this method explicitly, test succeeds
public void Subscribe()
{
// Subscribe to forward events outside the constructor
_cam.VisualDetected += VisualDetected;
}
}
下面是单元测试。
第一次测试:在构造函数中,Alarm对象订阅了ICam的事件,但是在单元测试中,当我引发ICam模拟对象的事件时,Alarm的事件未引发。
[Fact]
public void Alarm_SubscribesInCtor()
{
var cam = new Mock<ICam>();
var alarm = new Alarm(cam.Object);
var raised = false;
alarm.VisualDetected += (o, e) => raised = true;
cam.Raise(c => c.VisualDetected += null, new EventArgs());
Assert.True(raised); // FAILS
}
第二个测试:显式调用 Subscribe 方法,测试通过。
[Fact]
public void Alarm_SubscribesOutsideCtor()
{
var cam = new Mock<ICam>();
var alarm = new Alarm(cam.Object);
var raised = false;
alarm.VisualDetected += (o, e) => raised = true;
alarm.Subscribe();
cam.Raise(c => c.VisualDetected += null, new EventArgs());
Assert.True(raised); // SUCCEEDS
}
这个问题似乎是由于模拟对象初始化阶段的某种惰性造成的,但我不确定。
是否有任何解决方案或任何其他方式来确保事件订阅?
问题不是最小起订量,问题是您的代码:
_cam.VisualDetected += VisualDetected;
在这里,您添加来自 this
的 VisualDetected
事件的所有代表,并将它们附加到 _cam
的 VisualDetected
事件。
您的问题是此时 this
事件的 VisualDetected
没有代表,因此没有代表被添加到 _cam.VisualDetected
.
稍后向 alarm.VisualDetected
添加处理程序不会影响 _cam.VisualDetected
(并且不会向其添加该处理程序)。
如果你想 "forward" 事件,你可以简单地将一个处理程序附加到 _cam.VisualDetected
调用 this.VisualDetected
:
public Alarm(ICam cam)
{
_cam = cam;
_cam.VisualDetected += (s, e) =>
{
if(VisualDetected != null)
VisualDetected(this, e);
};
}
我在单元测试 (xUnit) 中使用 Moq(4.2.1502.911)。在构造函数中,被构造的对象试图订阅依赖事件(参数),但它似乎不起作用。
下面的代码是模拟问题的例子。 Alarm class 使用 ICam 接口依赖性在有物体移动时发出警报。
public interface ICam
{
event EventHandler VisualDetected;
}
public class Alarm : ICam
{
private ICam _cam;
public Alarm(ICam cam)
{
_cam = cam;
// Subscribe to forward events, DOES NOT WORK
_cam.VisualDetected += VisualDetected;
}
public event EventHandler VisualDetected;
// If I call this method explicitly, test succeeds
public void Subscribe()
{
// Subscribe to forward events outside the constructor
_cam.VisualDetected += VisualDetected;
}
}
下面是单元测试。
第一次测试:在构造函数中,Alarm对象订阅了ICam的事件,但是在单元测试中,当我引发ICam模拟对象的事件时,Alarm的事件未引发。
[Fact]
public void Alarm_SubscribesInCtor()
{
var cam = new Mock<ICam>();
var alarm = new Alarm(cam.Object);
var raised = false;
alarm.VisualDetected += (o, e) => raised = true;
cam.Raise(c => c.VisualDetected += null, new EventArgs());
Assert.True(raised); // FAILS
}
第二个测试:显式调用 Subscribe 方法,测试通过。
[Fact]
public void Alarm_SubscribesOutsideCtor()
{
var cam = new Mock<ICam>();
var alarm = new Alarm(cam.Object);
var raised = false;
alarm.VisualDetected += (o, e) => raised = true;
alarm.Subscribe();
cam.Raise(c => c.VisualDetected += null, new EventArgs());
Assert.True(raised); // SUCCEEDS
}
这个问题似乎是由于模拟对象初始化阶段的某种惰性造成的,但我不确定。
是否有任何解决方案或任何其他方式来确保事件订阅?
问题不是最小起订量,问题是您的代码:
_cam.VisualDetected += VisualDetected;
在这里,您添加来自 this
的 VisualDetected
事件的所有代表,并将它们附加到 _cam
的 VisualDetected
事件。
您的问题是此时 this
事件的 VisualDetected
没有代表,因此没有代表被添加到 _cam.VisualDetected
.
稍后向 alarm.VisualDetected
添加处理程序不会影响 _cam.VisualDetected
(并且不会向其添加该处理程序)。
如果你想 "forward" 事件,你可以简单地将一个处理程序附加到 _cam.VisualDetected
调用 this.VisualDetected
:
public Alarm(ICam cam)
{
_cam = cam;
_cam.VisualDetected += (s, e) =>
{
if(VisualDetected != null)
VisualDetected(this, e);
};
}