C# Moq:设置作为多个接口一部分的属性的简单方法
我尝试用以下结构(简化)模拟一些接口: 我遇到的问题是DateCreated对于每个接口都是一个单独的属性,因此即使我知道的具体对象只有这些共享属性的一个共享实现,调用Mock.SetupAllProperties也会为每个接口提供一个单独的实现。这意味着它们不共享值,因此当访问((A)obj).DateCreated时,调用((B)obj).DateCreated={blah}不会在别处给出所需的结果 我认为在Moq中解决此问题的唯一方法是执行以下操作:C# Moq:设置作为多个接口一部分的属性的简单方法,c#,moq,C#,Moq,我尝试用以下结构(简化)模拟一些接口: 我遇到的问题是DateCreated对于每个接口都是一个单独的属性,因此即使我知道的具体对象只有这些共享属性的一个共享实现,调用Mock.SetupAllProperties也会为每个接口提供一个单独的实现。这意味着它们不共享值,因此当访问((A)obj).DateCreated时,调用((B)obj).DateCreated={blah}不会在别处给出所需的结果 我认为在Moq中解决此问题的唯一方法是执行以下操作: var m = new Mock<
var m = new Mock<B>();
DateTime closure;
m.SetupGet(x => x.DateCreated).Returns(() => closure);
m.SetupSet(x => x.DateCreated).Callback(value => { closure = value; });
m.As<A>.SetupGet(x => x.DateCreated).Returns(() => closure);
m.As<A>.SetupSet(x => x.DateCreated).Callback(value => { closure = value; });
由于B和A都有一个名称和类型相同的属性,因此单个属性为它们提供服务。似乎因为在实际代码中有一种简单的方法来实现这一点,所以应该有一种同样简单的方法来使用Moq实现这一点 在重新阅读了你的问题(我一定没有醒着)之后,我意识到我完全没有领会你的意思。我看不出一个简单的方法来做你想做的事情,但是如果你想生活在危险之中,你可以通过只设置基本接口的属性来滥用我在下面提到的bug:
[Test]
public void Constructor_Always_Succeeds()
{
var mockOfB = new Mock<B>();
var mockOfA = mockOfB.As<A>();
mockOfA.SetupProperty(p => p.DateCreated);
B b = mockOfB.Object;
A a = b;
DateTime aTime = DateTime.Now;
DateTime bTime = DateTime.Now.AddDays(-1);
a.DateCreated = aTime;
Assert.That(a.DateCreated, Is.EqualTo(aTime));
Assert.That(b.DateCreated, Is.EqualTo(aTime));
b.DateCreated = bTime;
Assert.That(a.DateCreated, Is.EqualTo(bTime));
Assert.That(b.DateCreated, Is.EqualTo(bTime));
}
在这种情况下,它在第一次断言时失败,因为对DateCreated
的两个调用都返回aTime
。这是因为Moq在内部是如何工作的,但我不愿意称之为bug和错误。当拦截对属性的调用时,将找到与之匹配的安装程序:
换句话说,“查找可用于此调用的匹配项的最后一个设置。”因为我们设置了a.DateCreated
last,所以它可以用作B
或a
的DateCreated
属性的调用
也许这种情况内部应该得到处理。我本来想说“只使用
As()
”,但我自己无法做到……让B
中的一个成员在a
中隐藏一个成员似乎是个值得怀疑的想法。由于您似乎甚至没有使用new
关键字,您应该会得到一个编译器警告,即B
中的成员DateCreated
隐藏了从a
继承到B
的同名成员。如果您可以从B
中删除“复制”成员,并只使用继承的成员,这将解决所有问题。是的,我同意,这将是最好的方法。但正如我所说,我不能只是去修改我们公共库中的代码。我只是注意到没有警告,因为项目的警告级别设置为零!啊!据我所知,OP所追求的是一个共享实现(即两个属性应始终返回相同的值),与您的第一个代码片段不同。@Lucastzesniewski是的,您是对的,我误读了所需的行为。更新了我的答案。谢谢呃,事实上,在另一次阅读之后,我看到了OP真正想要的东西,但我没有完全回答它…是的,我真的不喜欢滥用这样一个bug的想法,因为谁知道一旦修复了它会发生什么?我正在考虑编写一个扩展方法来处理这个问题,但在不丢失简化语法的类型推断的情况下,这可能是一个相当具有挑战性的任务。
class C : B
{
public DateTime DateCreated { get; set; }
}
[Test]
public void Constructor_Always_Succeeds()
{
var mockOfB = new Mock<B>();
var mockOfA = mockOfB.As<A>();
mockOfA.SetupProperty(p => p.DateCreated);
B b = mockOfB.Object;
A a = b;
DateTime aTime = DateTime.Now;
DateTime bTime = DateTime.Now.AddDays(-1);
a.DateCreated = aTime;
Assert.That(a.DateCreated, Is.EqualTo(aTime));
Assert.That(b.DateCreated, Is.EqualTo(aTime));
b.DateCreated = bTime;
Assert.That(a.DateCreated, Is.EqualTo(bTime));
Assert.That(b.DateCreated, Is.EqualTo(bTime));
}
[Test]
public void Constructor_Always_Succeeds()
{
var mockOfB = new Mock<B>();
var mockOfA = mockOfB.As<A>();
DateTime dateTime = DateTime.Now;
mockOfA.SetupGet(p => p.DateCreated).Returns(dateTime);
mockOfB.SetupGet(p => p.DateCreated).Returns(dateTime);
B b = mockOfB.Object;
A a = b;
Assert.That(b.DateCreated, Is.EqualTo(dateTime));
Assert.That(a.DateCreated, Is.EqualTo(dateTime));
}
[Test]
public void Constructor_Always_Succeeds()
{
var mockOfB = new Mock<B>();
var mockOfA = mockOfB.As<A>();
DateTime aTime = DateTime.Now;
DateTime bTime = DateTime.Now.AddDays(-1);
// only difference, these two lines are swapped
mockOfB.SetupGet(p => p.DateCreated).Returns(bTime);
mockOfA.SetupGet(p => p.DateCreated).Returns(aTime);
B b = mockOfB.Object;
A a = b;
Assert.That(b.DateCreated, Is.EqualTo(bTime));
Assert.That(a.DateCreated, Is.EqualTo(aTime));
}
localctx.Call = FluentMockContext.IsActive ?
(IProxyCall)null :
ctx.OrderedCalls.LastOrDefault(c => c.Matches(invocation));