gpt4 book ai didi

c# - Moq:设置属于多个接口(interface)的属性的简单方法

转载 作者:太空狗 更新时间:2023-10-30 01:18:16 25 4
gpt4 key购买 nike

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

interface A 
{
DateTime DateCreated { get; set; }
}
interface B : A
{
DateTime DateCreated { get; set; }
}

我遇到的问题是 DateCreated 是每个接口(interface)的单独属性,因此即使我知道的具体对象只有这些共享属性的一个共享实现,调用 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; });

这很乏味,容易出错,我需要为至少十二个属性执行此操作,我不知道还有多少。我可能可以编写一个通用方法来执行此操作,但似乎必须有一个更简单的解决方案。谁能建议更好的方法来做到这一点?

(我很想“更正”接口(interface)的定义,但这段代码是我们整个组织共享的公共(public)遗留代码。由于这是一个潜在的破坏性变化,我不能随心所欲地进行修改-妮莉。)

编辑:澄清一下,我想要的是一种能够用 Moq 完成与此等效的简单方法:

class C : B
{
public DateTime DateCreated { get; set; }
}

因为 B 和 A 都有一个名称和类型都相同的属性,所以这个属性同时服务于他们两个。似乎因为在实际代码中有一种简单的方法可以做到这一点,所以应该有一种同样简单的方法来使用 Moq 来做到这一点。

最佳答案

在重新阅读您的问题后(​​我一定没有清醒),我意识到我完全没有理解您的观点。我没有看到一种简单的方法来做你想做的事,但如果你想过着危险的生活,你可以通过仅设置基本接口(interface)的属性来滥用我在下面提到的错误:

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

这回答了我认为被问到的问题,而不是实际被问到的问题

我能够使用 As<>() 让它工作,但有一个转折。这是我的测试:

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

该测试通过,并且在不了解您的实际情况的情况下应该适合您。


但是,在最初测试时我有 SetupGet调用反转(并且认为你想要不同的返回值),就像这样:

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

在那种情况下,它在第一个断言时失败,因为两次调用 DateCreated返回 aTime .这是因为最小起订量在内部的工作方式,但我不愿将其称为错误there is a bug filed for it .当对该属性的调用被拦截时,匹配它的设置是用 the following code 找到的:

localctx.Call = FluentMockContext.IsActive ? 
(IProxyCall)null :
ctx.OrderedCalls.LastOrDefault(c => c.Matches(invocation));

换句话说,“找到可用作此调用匹配项的最后一个设置。”由于我们设置了 A.DateCreated最后,它可以用作 B 的调用。或 ADateCreated属性(property)。

可能在 MethodCall.Matches 里面这种情况应该得到处理。

关于c# - Moq:设置属于多个接口(interface)的属性的简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28078579/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com