- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
public partial class Person
{
public virtual int PersonId { get; internal protected set; }
public virtual string Title { get; internal protected set; }
public virtual string FirstName { get; internal protected set; }
public virtual string MiddleName { get; internal protected set; }
public virtual string LastName { get; internal protected set; }
}
这就是它的行为:
public static class Services
{
public static void UpdatePerson(Person p, string firstName, string lastName)
{
// validate firstname and lastname
// if there's a curse word, throw an exception
// if valid, continue
p.FirstName = firstName;
p.LastName = lastName;
p.ModifiedDate = DateTime.Now;
}
}
而且它几乎是可测试的:
[TestMethod]
public void Is_Person_ModifiedDate_If_Updated()
{
// Arrange
var p = new Mock<Person>();
// Act
Services.UpdatePerson(p.Object, "John", "Lennon");
// Assert
p.VerifySet(x => x.ModifiedDate = It.IsAny<DateTime>());
}
但是,我想实践富域模型,其中数据和行为在逻辑上更具凝聚力。所以上面的代码现在转换为:
public partial class Person
{
public virtual int PersonId { get; internal protected set; }
public virtual string Title { get; internal protected set; }
public virtual string FirstName { get; internal protected set; }
public virtual string MiddleName { get; internal protected set; }
public virtual string LastName { get; internal protected set; }
public virtual void UpdatePerson(string firstName, string lastName)
{
// validate firstname and lastname
// if there's a curse word, throw an exception
// if valid, continue
this.FirstName = firstName;
this.LastName = lastName;
this.ModifiedDate = DateTime.Now;
}
}
但是我遇到测试问题:
[TestMethod]
public void Is_Person_ModifiedDate_If_Updated()
{
// Arrange
var p = new Mock<Person>();
// Act
p.Object.UpdatePerson("John", "Lennon");
// Assert
p.VerifySet(x => x.ModifiedDate = It.IsAny<DateTime>());
}
单元测试错误:
Result Message:
Test method Is_Person_ModifiedDate_If_Updated threw exception:
Moq.MockException:
Expected invocation on the mock at least once, but was never performed: x => x.ModifiedDate = It.IsAny<DateTime>()
No setups configured.
Performed invocations:
Person.UpdatePerson("John", "Lennon")
Result StackTrace:
at Moq.Mock.ThrowVerifyException(MethodCall expected, IEnumerable`1 setups, IEnumerable`1 actualCalls, Expression expression, Times times, Int32 callCount)
at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times)
at Moq.Mock.VerifySet[T](Mock`1 mock, Action`1 setterExpression, Times times, String failMessage)
at Moq.Mock`1.VerifySet(Action`1 setterExpression)
at Is_Person_ModifiedDate_If_Updated()
看到直接从模拟的对象调用方法,模拟的对象无法检测是否调用了其任何属性或方法。注意到这一点后,对富域模型进行单元测试的正确方法是什么?
最佳答案
首先,don't mock value objects或您正在测试的类(class)。此外,您也没有验证是否向人员提供了正确的修改日期。您检查是否已指定某个日期。但这并不能证明您的代码按预期工作。为了测试此类代码,您应该 mock current date由 DateTime.Now 或 create some abstraction 返回,这将提供当前的服务时间。您的第一个测试应该如下所示(我在这里使用 Fluent Assertions 和 NUnit):
[Test]
public void Should_Update_Person_When_Name_Is_Correct()
{
// Arrange
var p = new Person(); // person is a real class
var timeProviderMock = new Mock<ITimeProvider>();
var time = DateTime.Now;
timeProviderMock.Setup(tp => tp.GetCurrentTime()).Returns(time);
Services.TimeProvider = timeProviderMock.Object;
// Act
Services.UpdatePerson(p, "John", "Lennon");
// Assert
p.FirstName.Should().Be("John");
p.LastName.Should().Be("Lennon");
p.ModifiedDate.Should().Be(time); // verify that correct date was set
timeProviderMock.VerifyAll();
}
时间提供者是一个简单的抽象:
public interface ITimeProvider
{
DateTime GetCurrentTime();
}
我会选择单例服务而不是静态类,因为静态类总是有问题——高耦合、没有抽象、难以对依赖类进行单元测试。但是您可以通过属性注入(inject)时间提供程序:
public static class Services
{
public static ITimeProvider TimeProvider { get; set; }
public static void UpdatePerson(Person p, string firstName, string lastName)
{
p.FirstName = firstName;
p.LastName = lastName;
p.ModifiedDate = TimeProvider.GetCurrentTime();
}
}
这与你的第二次测试有关。不要模拟您正在测试的对象。您应该验证应用程序将使用的真实代码,而不是测试仅由测试使用的一些模拟。使用到达域模型进行的测试将如下所示:
[Test]
public void Should_Update_Person_When_Name_Is_Correct()
{
// Arrange
var timeProviderMock = new Mock<ITimeProvider>();
var time = DateTime.Now;
timeProviderMock.Setup(tp => tp.GetCurrentTime()).Returns(time);
var p = new Person(timeProviderMock.Object); // person is a real class
// Act
p.Update("John", "Lennon");
// Assert
p.FirstName.Should().Be("John");
p.LastName.Should().Be("Lennon");
p.ModifiedDate.Should().Be(time); // verify that correct date was set
timeProviderMock.VerifyAll();
}
关于c# - 单元测试丰富的领域模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20852190/
我想用个人详细信息来丰富订单集合。 假设我已经(示例在 json 中): [ { "orderId": 123, "quantity": 5, "buyerI
def classify(numb): i=1 j=1 sum=0 for i in range(numb): for j in range(numb)
我正在尝试使用 Spark 处理来自 HBase 表的数据。 This blog post给出了如何使用 NewHadoopAPI 从任何 Hadoop InputFormat 读取数据的示例。 我做
我使用 rich:menuitem 在 Richfaces 上构建了菜单。我需要确定用户单击了哪个菜单项。我尝试使用: 但是,我在请求参数中没有看到参数
注意:我遗漏了不相关的代码 所以我目前正在研究 CCC 1996 P1,这个问题的全部目的是能够计算一个整数输入是完美数、不足数还是充数。我上面列出的代码可以工作,但是我认为它太慢了。该代码会迭代每个
我们正在考虑将 ACS 作为我们的联合 STS。我们可以将自己的自定义 STS 配置为 IP-STS,以及“内置”身份提供商,例如 Facebook、Live 和 Google。然而,我们收到的 cl
我使用以下命令成功创建了一个绘图: # suppose I have a p <- ggplot(data=df, ...) then the following works # I get thos
我正在使用 spring-data-rest 存储库从 REST API 公开常见的 CRUD 操作。 但是我需要为这些操作添加额外的功能。 例如我想向第三方 API 发送关于删除的 HTTP 请求。
我有一个java支持bean,它有一个方法(称之为getDataList()),它返回ArrayList . 在 MyType.java我有很多 setter 和 getter,它们都分配 Strin
我正在使用以下代码:
我正在尝试在facelet组合中使用rich:faces组件rich:jQuery。但我无法产生任何 jquery 调用。 另一个问题...我将如何重写它以落入第一模式
是否可以将 Firebase 上游消息作为可操作通知进行传递?这就是我想要实现的目标:我希望能够将可操作的上游 Firebase 消息从我的 iPad 发送到我的 iPhone。 这可能吗? 这是我的
我有richfaces应用程序。在页面中,定义了 jQuery 函数: 然后我有一些 a4j:commandLink,它应该在完成 ajax 请求时调用该函数。 不幸的是,它不起作用。我知道 on
我有一个 rich:tree 组件,如下使用:
对于客户,我们需要为集成测试生成详细的测试报告,这些报告不仅表明一切都是绿色的,而且还表明测试做了什么。我和我的同事都很懒惰,我们不想破解电子表格或文本文档。 为此,我想了一种方法来记录更复杂的集成测
我在构建 Clojure 时遇到了一些困难基于 Web 应用程序。这是一个简单的 CRUD 应用程序,我开始探索 Clojure 网络生态系统。我正在尝试不同的库,例如 Hiccup , Enlive
我正在编写一个 Flink 流程序,其中我需要使用一些静态数据集(信息库,IB)来丰富用户事件的 DataStream。 对于例如假设我们有一个买家的静态数据集,并且有一个传入的事件点击流,对于每个事
在我的应用程序中,我有一个记录列表。用户可以选择任何记录,更新选项菜单。表格显示了这些记录,它有分页。 所以问题是,当我选择一条记录并对列表进行排序(使我之前选择的记录转到另一个页面)时,我看不到所选
我有一棵树(父级可以有任意数量的子级)和一个用于按名称搜索节点的 inputText 。假设有以下树: A --A1 ----AA1 --A2 其中 A 有两个子级 A1 和 A2,A1 有一个子级
我有一个 rich:dataTable 和一个 rich:dataScroller。当我单击 datascroller 时,我的 dataTable 不会自动刷新以显示正确的页面。但是,如果我按下刷新
我是一名优秀的程序员,十分优秀!