Service 还有一个关于嘲笑的问题
首先让我声明,尽管我是TDD的一个相当新的实践者,但我对它的好处非常满意。我觉得我已经有足够的进步去考虑使用嘲讽,并且在理解MOOK与OOP相适应时,打了一个真正的砖墙。 我已经阅读了尽可能多的关于这个主题的相关帖子/文章(,),但仍然不完全清楚如何或何时嘲笑 让我举一个具体的例子。我的应用程序有一个服务层类(有人称之为应用层?),其中的方法大致映射到特定用例。这些类可以与持久层、域层甚至其他服务类协作。我一直是一个很好的DI小男孩,并且已经正确地考虑了我的依赖性,所以它们可以作为测试目的的子平台 示例服务类可能如下所示:Service 还有一个关于嘲笑的问题,service,mocking,encapsulation,Service,Mocking,Encapsulation,首先让我声明,尽管我是TDD的一个相当新的实践者,但我对它的好处非常满意。我觉得我已经有足够的进步去考虑使用嘲讽,并且在理解MOOK与OOP相适应时,打了一个真正的砖墙。 我已经阅读了尽可能多的关于这个主题的相关帖子/文章(,),但仍然不完全清楚如何或何时嘲笑 让我举一个具体的例子。我的应用程序有一个服务层类(有人称之为应用层?),其中的方法大致映射到特定用例。这些类可以与持久层、域层甚至其他服务类协作。我一直是一个很好的DI小男孩,并且已经正确地考虑了我的依赖性,所以它们可以作为测试目的的子平
public class AddDocumentEventService : IAddDocumentEventService
{
public IDocumentDao DocumentDao
{
get { return _documentDao; }
set { _documentDao = value; }
}
public IPatientSnapshotService PatientSnapshotService
{
get { return _patientSnapshotService; }
set { _patientSnapshotService = value; }
}
public TransactionResponse AddEvent(EventSection eventSection)
{
TransactionResponse response = new TransactionResponse();
response.Successful = false;
if (eventSection.IsValid(response.ValidationErrors))
{
DocumentDao.SaveNewEvent( eventSection, docDataID);
int patientAccountId = DocumentDao.GetPatientAccountIdForDocument(docDataID);
int patientSnapshotId =PatientSnapshotService.SaveEventSnapshot(patientAccountId, eventSection.EventId);
if (patientSnapshotId == 0)
{
throw new Exception("Unable to save Patient Snapshot!");
}
response.Successful = true;
}
return response;
}
}
我使用NMock在隔离依赖项(DocumentDao、PatientSnapshotService)的情况下测试了这个方法。下面是测试结果
[Test]
public void AddEvent()
{
Mockery mocks = new Mockery();
IAddDocumentEventService service = new AddDocumentEventService();
IDocumentDao mockDocumentDao = mocks.NewMock<IDocumentDao>();
IPatientSnapshotService mockPatientSnapshot = mocks.NewMock<IPatientSnapshotService>();
EventSection eventSection = new EventSection();
//set up our mock expectations
Expect.Once.On(mockDocumentDao).Method("GetPatientAccountIdForDocument").WithAnyArguments();
Expect.Once.On(mockPatientSnapshot).Method("SaveEventSnapshot").WithAnyArguments();
Expect.Once.On(mockDocumentDao).Method("SaveNewEvent").WithAnyArguments();
//pass in our mocks as dependencies to the class under test
((AddDocumentEventService)service).DocumentDao = mockDocumentDao;
((AddDocumentEventService)service).PatientSnapshotService = mockPatientSnapshot;
//call the method under test
service.AddEvent(eventSection);
//verify that all expectations have been met
mocks.VerifyAllExpectationsHaveBeenMet();
}
[测试]
公共事务
{
mockry mocks=新mockry();
IADDocumentEventService服务=新的AddDocumentEventService();
IDocumentDao mockDocumentDao=mocks.NewMock();
IPatientSnapshotService mockPatientSnapshot=mocks.NewMock();
EventSection EventSection=新的EventSection();
//设定我们的模拟期望
Expect.Once.On(mockDocumentDao.Method)(“GetPatientAccountIdForDocument”).WithAnyArguments();
Expect.Once.On(mockPatientSnapshot.Method(“SaveEventSnapshot”).WithAnyArguments();
Expect.Once.On(mockDocumentDao.Method(“SaveNewEvent”).WithAnyArguments();
//将模拟作为依赖项传递给被测试的类
((AddDocumentEventService)服务).DocumentDao=mockDocumentDao;
((AddDocumentEventService)服务).PatientSnapshotService=mockPatientSnapshot;
//调用被测试的方法
服务.附录(事件部分);
//验证是否满足了所有期望
mocks.VerifyAllExpectationsHaveBeenMet();
}
我对这场小小的嘲弄之旅的想法如下:
我遗漏了什么?你提到了马丁·福勒关于这个主题的一篇非常好的帖子。他提到的一点是,嘲弄者喜欢测试行为,并孤立事物 “经典的TDD风格是在可能的情况下使用真实对象,如果使用真实对象有困难,则使用双精度。因此,经典的TDD将使用真实仓库和双精度邮件服务。双精度的类型实际上并不重要 然而,mockist TDD实践者总是对任何具有有趣行为的对象使用mock。在这种情况下,对仓库和邮件服务都使用mock。” 如果你不喜欢这类东西,你可能是一个典型的TDDer,只有在不方便的时候才应该使用Mock(比如邮件服务,或者信用卡收费)否则,您将创建自己的翻倍(就像创建内存中的数据库一样) 特别是,我是一个mockist,但我不会验证是否调用了特定的方法(除非它不返回值)。在任何情况下,我都会测试接口。当函数返回某些内容时,我使用模拟框架创建存根 最后,所有内容都包括您想要测试的内容和方式。您认为检查这些方法是否真的被调用(使用mock)很重要吗?您是否只想检查通话前后的状态(使用假货)<强>选择足以考虑它正在工作,然后建立你的测试来精确地检查它!<强> 关于测试的价值,我有一些看法:
- 短期而言,当您进行TDD时,通常会得到更好的设计,尽管您可能需要更长的时间
- 从长远来看,您不会太害怕在以后更改和维护此代码(当您记不清详细信息时),您会立即收到红色,几乎是即时反馈
顺便说一下,测试代码大小与生产代码大小一样大是正常的。您提到了martin fowler关于这个主题的一篇非常好的帖子。他提到的一点是,嘲弄者喜欢测试行为,并孤立事物 “经典的TDD风格是在可能的情况下使用真实对象,如果使用真实对象有困难,则使用双精度。因此,经典的TDD将使用真实仓库和双精度邮件服务。双精度的类型实际上并不重要 然而,mockist TDD实践者总是对任何具有有趣行为的对象使用mock。在这种情况下,对仓库和邮件服务都使用mock。” 如果你不喜欢这类东西,你可能是一个典型的TDDer,只有在不方便的时候才应该使用Mock(比如邮件服务,或者信用卡收费)否则,您将创建自己的翻倍(就像创建内存中的数据库一样) 特别是,我是一个mockist,但我不会验证是否调用了特定的方法(除非它不返回值)。在任何情况下,我都会测试接口。当函数返回某些内容时,我使用模拟框架创建存根 最后,
Instantiate the fake repositories.
Run your test method.
Check the fake repository to see if the new elements exist in it.
public void AddEventSavesSnapshot(object eventSnaphot)
{
Mock<IDocumentDao> mockDocumentDao = new Mock<IDocumentDao>();
Mock<IPatientSnapshotService> mockPatientSnapshot = new Mock<IPatientSnapshotService>();
string eventSample = Some.String();
EventSection eventSection = new EventSection(eventSample);
mockPatientSnapshot.Setup(r => r.SaveEventSnapshot(eventSample));
AddDocumentEventService sut = new AddDocumentEventService();
sut.DocumentDao = mockDocumentDao;
sut.PatientSnapshotService = mockPatientSnapshot;
sut.AddEvent(eventSection);
mockPatientSnapshot.Verify();
}