自动生成遗留Java代码的单元测试

自动生成遗留Java代码的单元测试

Auto-generating Unit-Tests for legacy Java-code

什么是最好的,最好是免费/开源的工具,用于自动生成Java单元测试?我知道,单元测试不能真正起到与普通TDD单元测试相同的作用,后者可以记录和驱动系统的设计。但是,如果您拥有庞大的旧版代码库,并且想知道是否需要进行更改,那么自动生成的单元测试可能会很有用。


不是免费的。不是开源的。但是我发现AgitarOne搅拌器(http://www.agitar.com/solutions/products/agitarone.html)确实非常适合自动生成单元测试并查找不必要的晦涩副作用


用于Eclipse的Coview插件(http://www.codign.com/products.html)看起来只是工作。我对生成覆盖代码中所有路径的测试很感兴趣,这似乎可以做到。它还生成了模拟程序,应该可以节省大量时间。


这很有趣,但是这种生成的单元测试实际上是有用的。如果您使用的是旧版应用程序,通常很难编写正确的最新单元测试。

这样生成的测试(当然,如果您有生成它们的方法)可以确保代码行为在更改期间保持不变,这可以帮助您重构代码并编写更好的测试。

现在要生成自己。我不知道任何魔术工具,但是您可能希望搜索有关在Javadocs中包含一些测试方法的JUnit功能。这将允许您编写一些简单的测试。是的,它实际上具有一定的价值。

第二,您可以手动编写" big "测试。当然,这些本身并不是单元测试(没有隔离,潜在的副作用等),但是可能是很好的第一步。尤其是如果您的时间很少并且有旧版应用程序。

奖金提示!有一本很棒的书"有效地处理遗留代码",其中包含Java实例,其中包括在这种情况下可以使用的技术。不幸的是,您必须手动执行某些操作,但是无论如何您都必须在某些步骤中执行该操作。


说实话,我可能不会这样做。单元测试是隔离的,您实际上不会知道自己是否具有"有害的,晦涩的副作用",因为所有内容都与导致副作用的其他因素隔离开来。结果,您需要集成或系统测试,而这不能自动化。

构建一些高级的,端到端的系统测试,这些测试可以给您一定的信心,然后使用覆盖率测试来找出您遗漏的内容,缺点是当出现错误时,它会很难指出它们的确切原因,但好处是您更有可能看到这些错误。

一旦发现错误,就只为它们编写单元测试。继续前进时,可以将TDD用于要重构的位。

我知道这可能不是您想听到的答案,但是我已经进行了很多年的测试,这是一个可靠的方法(尽管我很难将其称为唯一的方法:) >


Diffblue Cover是执行此操作的产品,并且有一个免费的Community Edition,它是IntelliJ插件,在这里:https://plugins.jetbrains.com/plugin/14946-diffblue-cover-community-edition --unit-test-generator

它通过强化学习来搜索可能有用的测试的空间,并努力编写类似于人类的测试。它会自动创建模拟并具有完整的Spring / SpringBoot支持。

这是在Spring PetClinic中针对所有者控制器编写的示例测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void testInitUpdateOwnerForm() throws Exception {
    Owner owner = new Owner();
    owner.setLastName("Doe");
    owner.setId(1);
    owner.setCity("Oxford");
    owner.setPetsInternal(new HashSet<Pet>());
    owner.setAddress("42 Main St");
    owner.setFirstName("Jane");
    owner.setTelephone("4105551212");
    when(this.ownerRepository.findById(or(isA(Integer.class), isNull()))).thenReturn(owner);
    MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/owners/{ownerId}/edit", 123456789);
    ResultActions actualPerformResult = this.mockMvc.perform(requestBuilder);
    ResultActions resultActions = actualPerformResult.andExpect(MockMvcResultMatchers.status().isOk());
    ResultActions resultActions1 = resultActions.andExpect(MockMvcResultMatchers.model().size(1));
    resultActions1.andExpect(MockMvcResultMatchers.model().attributeExists("owner"));
}

推荐阅读