为什么测试也需要重构?

我们在使用TDD的时候, 会不断添加测试, 这是因为我们需要通过这些测试去驱动完成我们的功能。

但是并不意味着我们获得的测试就是一个良好的测试,我们也需要对这些测试用例进行进一步的重构, 比如我们观察下面的测试代码。

@Test
public void should_throw_exception_if_dependency_not_found() {
   
    setup();
    config.bind(Component.class, ComponentWithInjectConstructor.class);

    DependencyNotFoundException exception = assertThrows(DependencyNotFoundException.class, () -> {
   
        config.getContext();
    });

    assertEquals(Dependency.class, exception.getDependency());
    assertEquals(Component.class, exception.getComponent());
}

@Test
public void should_throw_exception_if_transitive_dependency_not_found() {
   
    setup();
    config.bind(Component.class, ComponentWithInjectConstructor.class);
    config.bind(Dependency.class, DependencyWithInjectConstructor.class);

    DependencyNotFoundException exception = assertThrows(DependencyNotFoundException.class, ()-> {
   
        config.getContext();
    });
    assertEquals(String.class, exception.getDependency());
}

无论你是间接传递的, 还是直接传递, 这两个测试代码都是一样的,也就说这个是一个设计重复, 这两个东西就是我们在设计决策中产生的遗留。

因此需要重构来消除我们的测试构造中的留下来的不一样印记, 比如

  1. 之前的架构选择
  2. 之前设计上的这样的一些决策。
  3. 一些隐藏的测试不一致

通过重构测试去获得更好的组织测试, 才能够保证我们TDD进行之后, 我们得到了结构优秀的代码, 同时在我们的测试中, 真实反映了我们代码的那个意图。

删除重复测试

首先我们删除should_throw_exception_if_transitive_dependency_not_found测试函数, 然后创建一个dependencycheck类,
然后将dependency相关的处理的测试函数, 移到该类中。

然后我们处理关于constructor相关的测试用例, 我们发现constructor的测试用例是依赖于 ConstructorInjectionProvider实例的
我们希望将它重构new ConstructorInjectionProvider<>(implementation)

//提取方法
@Test
public void should_throw_exception_if_multi_inject_constructors_provide() {
   
    setup();

    assertThrows(IllegalComponentException.class, () -> {
   
        getBind();
    });
}

private void getBind() {
   
    config.bind(Component.class, ComponentWithMultiInjectConstructor.class);
}

//然后引入一个参数:
private void getBind(Class<? extends Component> implementation) {
   
        config.bind(Component.class, implementation);
}

@Test
public void should_throw_exception_if_have_no_inject_constructors_provide() {
   
    setup();

    assertThrows(IllegalComponentException.class, () -> {
   
        getBind(ComponentWithNoInjectConstructorNorDefaultConstructor.class);
    });
}

然后我们将 getBind() 中的内容转换成new ConstructorInjectionProvider<>(implementation); 然后inline回去。

将测试上下文保持一致

下一步我们就要将constructorInjectTest的结构和其它的两个测试methodInjectTest, FieldInjectTest测试保持一致。在后两个测试中我们针对ConstructorProvider进行了测试, 而在构造constructorInjectTest的时候并没有构造它, 为了保持一致, 我们也需要在constructor中针对ConstructorProvider进行测试。

@Test
public void should_include_dependency_from_inject_constructor() {
   
    ConstructorInjectionProvider<ComponentWithInjectConstructor> provider = new ConstructorInjectionProvider<>(ComponentWithInjectConstructor.class);
    assertArrayEquals(new Class<?>[]{
   Dependency.class}, provider.getDependencies().toArray(Class<?>[]::new));
}

然后我们将这三者包含在一起,命名为一个新的类叫做InjectTest, 然后移动出去。

class InjectorTest {
   
  class ConstructorTest {
   }
  class MethodInjectTest{
   }
  class FieldInjectTest{
   }
}

这样我的测试上下文就重构完成了, 所以写过的测试case并不是一成不变的, 它是会随着我们架构的改变而改变的。

相关推荐

  1. 为什么测试需要重构?

    2024-01-08 14:28:01       28 阅读
  2. 为什么需要数据仓库

    2024-01-08 14:28:01       34 阅读
  3. 为什么需要分布式存储

    2024-01-08 14:28:01       12 阅读
  4. 为什么需要 RAG?

    2024-01-08 14:28:01       6 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-08 14:28:01       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-08 14:28:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-08 14:28:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-08 14:28:01       18 阅读

热门阅读

  1. 基于单片机的集中供热监控电路设计

    2024-01-08 14:28:01       34 阅读
  2. python线程池提交任务

    2024-01-08 14:28:01       37 阅读
  3. 基于单片机的智能衣柜设计

    2024-01-08 14:28:01       33 阅读
  4. android启动流程

    2024-01-08 14:28:01       38 阅读
  5. Openharmony hdc启动关闭应用

    2024-01-08 14:28:01       43 阅读
  6. 05.构造程序逻辑

    2024-01-08 14:28:01       39 阅读
  7. Spring整合drools

    2024-01-08 14:28:01       32 阅读