测试1 如何细化测试场景,编写可测试的代码

163 阅读2分钟

设计先行,测试迭代

image.png

需求 设计先行

设计一个task模块

  • [添加一个 Task 项]
task add <item> 
1. <item> 
Item <itemIndex> added
  • [完成一个 Task 项]
task done <itemIndex> 
Item <itemIndex> done.
  • [Task 项列表] 列出指定task
task list 1. <item1> 2. <item2> 
Total: 2 items

列出所有task

task list --all 
1. <item1> 
2. <item2> 
3. [Done] <item3> 
Total: 3 items, 1 item done

领域服务设计

识别名词 -> TASK项服务

  • [addTodoItem,添加 Task 项]
  • [markTodoItemDone,完成一个 Task 项]
  • [list,列出所有的 Task 项]

Repository -> TASK项的持久化

任务分解

  • [ ADD接口 ]
TaskItem addTaskItem(final TaskItem item);

设计规范
1.对于输入参数的检测,由入口部分代码进行处理。
2.Repository 的问题以运行时异常的形式抛出,业务层不需要做任何处理。

测试场景
添加正常的参数对象,返回一个创建好的 Todo 项;
添加空的参数对象,抛出异常。

测试用例

@Test
public void should_add_task_item() {
    TaskRepository repository = mock(TaskRepository.class);
    when(repository.save(any())).then(returnsFirstArg());
    ITaskService service = new TaskService(repository);
    Task item = service.addTaskItem(new Task(0, "task1"));
    assertThat(item.getName()).isEqualTo("task1");
}
@Test
public void should_throw_exception_for_null_task_item() {
 assertThatExceptionOfType(IllegalArgumentException.class)
 .isThrownBy(() -> service.addTaskItem(null));
}

接口实现

public TaskItem addTaskItem(TaskItem item) {
    if (item == null) {
        throw new IllegalArgumentException("null or empty parameters is not allowed!");
    }
    return taskRepository.save(item);
}
  • [ MarkTaskDone接口 ]
Optional<TodoItem> markTaskItemDone(Task task);

测试场景
对于一个已经存在的 Todo 项,将其标记已完成;
如果索引超出现有的索引范围,则返回空。

测试用例

@BeforeEach
public void setUp() {
 this.repository = mock(TaskRepository.class);
 this.service = new TaskService(this.repository);
 }
 
@Test
public void should_mark_task_item_as_done() {
Task task = new Task(0, "task1");
 when(repository.findAll()).thenReturn(ImmutableList.of(new Task(0, "task1"))
 when(repository.save(any())).then(returnsFirstArg());
 
 final Optional<TodoItem> taskItem = service.markTaskItemDone(task);
 
 assertThat(taskItem).isPresent();
 final Task actual = taskItem.get();
 assertThat(actual.getStatus()).isTrue();
}

接口实现

public Optional<TodoItem> markTaskItemDone(TaskItem item) {
    if (item == null) {
        throw new IllegalArgumentException("null or empty parameters is not allowed!");
    }
    Optional<Task> optionalTask = repository.findById(item.getId());

    if (optionalTask.isPresent()) {
        item.setDone(true);
        repository.save(item);
    }
    return optionalTask;
}
  • [ List接口 ]
List<Task> list(final boolean all);

设计规范
all 参数为 true 时,列出所有的 Task 项;
false 的时候,列出未完成的 Task 项。

测试场景
如果有 Task 项,罗列 Task 项时,列出所有的 Task 项;
如果没有 Task 项,罗列 Task 项时,列出 Task 项为空;
如果有未完成的 Task 项,罗列未完成 Task 项,列出所有未完成的 Task 项;
如果没有未完成的 Task 项,罗列未完成 Task 项,列出的 Task 项为空。

测试用例

@BeforeEach
public void setUp() {
 this.repository = mock(TaskRepository.class);
 this.service = new TaskService(this.repository);
 }
 
@Test
public void list_all() {
Task task = new Task(0, "task1");
 when(repository.findAll()).thenReturn(ImmutableList.of(new Task(0, "task1"))
 List<Task> list = service.list(true);
 assertThat(list.size() == 1).isTrue();
}

@Test
public void list_all_empty() {
Task task = new Task(0, "task1");
 when(repository.findAll()).thenReturn(new ArrayList())
 List<Task> list = service.list(true);
 assertThat(list.size() == 0).isTrue();
}

list_false 如上

接口实现

public List<Task> list(final boolean all) {
List<Task> tasks = repository.findAll();
if(all) {
    return tasks;
}else{
    return repository.findAll().stream().filter(item -> item.getStatus().equals(true)).collect(Collectors.toList());
}
}