【发布时间】:2013-12-31 05:23:48
【问题描述】:
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()
看到直接从被模拟对象中调用方法,被模拟对象就无法检测到是否调用了它的任何属性或方法。注意到这一点后,对富域模型进行单元测试的正确方法是什么?
【问题讨论】:
-
感谢您取消删除,如下所示,写答案花了一些时间:)
-
更新方法,虽然如您所展示的那样有利于为验证目的进行封装,但实际上只是渗入域的事务性脚本。尝试打破用户的要求。他们是在更正此人姓名的拼写,还是更改此人的法定姓名。当然,这取决于您的应用程序,但请尝试考虑细粒度的请求以及执行时产生的行为。
标签: c# unit-testing moq rich-domain-model