我想测试应用层的类,不确定什么是更好的。我有Domain Model的类是Task,例如
class Task {
private Clock clock;
public Guid Id {get; private set;}
public string Name {get; set;}
public DateTime StartedDate {get; private set;}
public Task(Guid id, string name, Clock pClock) {
Id = id;
Name = name;
clock = pClock;
StartedDate = clock.Now();
}
}
interface Clock
{
DateTime Now {get;}
}
所以我想测试WorkManagementService类的CreateTask方法。我无法理解我应该测试什么。假设,我写了测试
TestCreateTaskShouldReturnTaskIdWasCreated()
{
Guid taskId = Guid.Empty;
TaskRepository repository = Substitute.For<TaskRepository>();
repsitory.Add(Arg.Do<Task>(taskArgument => taskId = taskArgument.Id));
var service = new WorkManagementService(repository);
var createdTaskId = service.CreateTask("task name");
Assert.AreNotEqual(Guid.Empty, createdTaskId);
Assert.AreEqual(taskId, createdTaskId);
}
所以,我不确定这是不是很好的做法。 CreateTask方法使用Task构造函数来创建Task和Clock接口的一些实现,因此WorkManagementService类依赖于它们。是一个好方法?
如果这令人困惑,我很抱歉。
更新 我认为CreateTask方法的第一个实现可能会跟随。
class WorkManegementService
{
private TaskRepository taskRepository;
public WorkManegementService(TaskRepository pTaskRepository)
{
taskRepository = pTaskRepository;
}
Guid CreateTask(string name)
{
var taskId = Guid.NewGuid();
var task = new Task(taskId, name, new SystemClock());
try
{
taskRepository.Save(task);
return taskId;
}
catch (...)
{
// some handling
}
}
}
在进一步实施期间,我将添加任务所有者或类似的东西。
答案 0 :(得分:2)
您可以测试对象的创建和正确初始化,但这里没有真正的逻辑可供测试。 如果您打算测试使用此任务的上下文,行为是什么会更好。
老实说,没有必要对简单的访问器和mutator进行单元测试。这是浪费时间,对任何人都没有帮助。测试创建的唯一原因是因为您希望对象存在特定状态...(例如游戏地图或银行帐户)。
**也许如果您显示Create方法代码,它将更好地概述您的方法应该做什么
[编辑]
您的测试可以验证您的保存方法已被调用...
repository.Received().Save(Arg.Any<Task>()); // Arg.Is if you prefer
更多here
[EDIT2]
对于依赖项,您可以完全将任务的初始化委托给另一个方法/类,这样您的测试就可以完全预测并与其他依赖项隔离。 从纯粹主义的角度来看,单元测试应该在当时测试一件事并且有限的理由失败。如果您正在学习,我会建议您严格遵守此规则。
Guid CreateTask(string name)
{
var task = this.InitTask(name); // or factory.CreateTask(name) or you can have public function prop that you inject if you like functional way...
try
{
taskRepository.Save(task);
return taskId;
}
catch (...)
{
// some handling
}
}
答案 1 :(得分:2)
单元测试的主要目的是确保应用程序的业务逻辑按预期工作。您必须在示例中测试的唯一业务逻辑是:
repository.Save
并且task
的内容正确对于Task
对象,您可以考虑进行测试以确保构造函数正常工作,但是对Clock
类进行单元测试以确保它按预期工作更为重要。
答案 2 :(得分:1)
在这里你问:
我有Clock和Task构造函数的测试,但似乎是正确的 CreateTask测试的执行取决于Task和Clock类。所以 test隐含地涵盖了3个类。或者我误解了吗?
Clock
和Task
构造函数测试是合适的,不需要在CreateTask()
测试中重复。
要汇总上述适当的指导,WorkManagementService
的正确测试如下:
CreateTask()
调用,然后确保按预期报告错误(例如,抛出ArgumentNullException
)< / LI>
CreateTask()
调用,然后确保使用适当的参数调用repository.Save()
(通过使用模拟的构造函数 - 注入存储库)CreateTask()
调用参数和失败repository.Save()
调用(抛出异常),然后确保CreateTask()
按预期失败(例如,重新抛出异常,抛出新的外部异常或其他预期的错误处理)repository.Save()
次调用,然后确保CreateTask()
返回预期的Guid