Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Moq:设置作为多个接口一部分的属性的简单方法_C#_Moq - Fatal编程技术网

C# Moq:设置作为多个接口一部分的属性的简单方法

C# Moq:设置作为多个接口一部分的属性的简单方法,c#,moq,C#,Moq,我尝试用以下结构(简化)模拟一些接口: 我遇到的问题是DateCreated对于每个接口都是一个单独的属性,因此即使我知道的具体对象只有这些共享属性的一个共享实现,调用Mock.SetupAllProperties也会为每个接口提供一个单独的实现。这意味着它们不共享值,因此当访问((A)obj).DateCreated时,调用((B)obj).DateCreated={blah}不会在别处给出所需的结果 我认为在Moq中解决此问题的唯一方法是执行以下操作: var m = new Mock<

我尝试用以下结构(简化)模拟一些接口:

我遇到的问题是DateCreated对于每个接口都是一个单独的属性,因此即使我知道的具体对象只有这些共享属性的一个共享实现,调用Mock.SetupAllProperties也会为每个接口提供一个单独的实现。这意味着它们不共享值,因此当访问((A)obj).DateCreated时,调用((B)obj).DateCreated={blah}不会在别处给出所需的结果

我认为在Moq中解决此问题的唯一方法是执行以下操作:

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));