Diffblue Cover AI实现Java自动化的单元测试工具
Diffblue Cover是一种自动化的单元测试编写工具。它分析您现有的Java应用程序,并编写反映当前行为的单元测试,从而增加测试范围并帮助您在将来的代码更改中查找回归。Cover在代码更改时通过更新测试来自动维护测试。Cover支持标准Java 8和11,Spring和Spring Boot。
Cover可以作为Windows和Linux的CLI工具使用,并且可以在您的Maven或Gradle环境中自行配置,可以100%自主运行。还有用于IntelliJ IDEA的Cover插件,用于交互式测试编写。
总部位于英国牛津大学的初创公司Diffblue对此深信不疑。周二,Diffblue宣 布其旗舰产品Diffblue Cover和Diffblue Cover: Community Edition全面上市,这是使用IntelliJ(最流行的企业Java IDE)为开发人员创建的免费版本。
https://www.diffblue.com/products/
它是如何工作的?
Diffblue Cover是适用于Linux和Windows的软件,可在您的计算机上本地运行100%。
您可以在整个Java项目中运行它,也可以只运行一个类,也可以在两者之间运行任何东西。它从Maven或Gradle获取您的项目结构和依赖关系。Cover支持Spring Java应用程序,并编写使用标准Spring习语和模拟的测试。
有两个Diffblue IntelliJ插件-完整的Cover IntelliJ插件和Cover Community Edition IntelliJ插件。Cover Community Edition是免费的,可以用于开放源代码项目;Cover的完整(收费)版本可用于任何项目,并获得Diffblue的全面支持。
下面和知识库中的文档介绍了此版本,并提供了完整的支持。
要获得免费的Community Edition Cover IntelliJ插件,请转到下载 页面。下面和知识库中的文档涵盖了此版本,但也可能包含Community Edition中不可用的功能。社区支持可从社区论坛获得。
IntelliJ版本2019.3或更高版本
Java 8或11源代码
基于Maven或Gradle的项目
2 GB最小存储器要求(修订本中的IntelliJ,选择Help然后Change Memory Settings)
您的项目必须编译并运行
Diffblue Cover将运行它为您的代码编写的测试,因此您的项目必须编译并运行,以使Cover正常工作。
您的项目配置(例如,pom.xml对于Maven项目)必须包括所有必需的依赖项,并且它们都必须已经构建或下载(例如,通过mvn clean install对Maven项目进行构建)。
JUnit始终是必需的依赖项。
如果它们是您项目的可传递依赖项,则可能需要下面列出的依赖项。
如果这些依赖关系中的一种是必需的,但是缺少,则会为某些类生成测试,而不会为其他类生成测试。
一条消息将出现在事件日志中,指示缺少依赖项。
请注意,您只能在一个项目上运行Cover IntelliJ插件的一个实例。不支持在同一项目上运行多个实例。
如果您不是直接从JetBrains市场安装,则将zip文件下载到合适的位置。
从IntelliJ IntelliJ IDEA -> Preferences(macOS)或File -> Settings(Windows / Linux)菜单中选择Plugins项目。
单击Installed窗口顶部选项卡右边的齿轮图标。从下拉菜单中选择Install Plugin from Disk…
导航到插件的位置,选择zip文件,然后单击Open。点击OK。
当提示您这样做时,请单击到Restart IDE,然后单击确定OK。
该CoreBanking应用程序是一个用于演示目的的简单银行应用程序,可以在https://github.com/diffblue/CoreBanking中找到。
在不加载项目的情况下启动IntelliJ以查看欢迎屏幕:
选择Get from Version Control选项。选择Git从版本控制下拉框。CoreBanking在存储库框中输入url,为项目选择合适的位置。然后,单击Clone。
使用Al, Diffblue可以以人 类可读的形式自动编写Java单元测试,覆盖率高达80%,随着代码的发展,即使在具有数百万行代码的应用程序上,它们也可以自动维护测试。
为了为当前未涵盖的类生成新的测试:
选择Project窗口。
选择CoreBanking-> src-> main-> java-> io.diffblue.corebanking-> account-> Account
。
右键单击并Write Tests从菜单中选择选项。
成功克隆后,展开下面的CoreBanking部分Project以查看源树。
该插件在分析代码和创建测试之前先构建项目。生成项目后,单击屏幕底部的进度栏以打开一个弹出窗口。
进度窗口将显示分析所经历的不同阶段。在分析代码时,可以查看当前进度,但是在较小的项目(例如)中CoreBanking,这是一个非常短的时间范围。
创建新测试后,它们将被自动集成到项目中src/test/java。
源代码编辑器中的各个类
源代码编辑器中的各个方法
源文件顶部的选项卡中的各个类 Project菜单中其类内的各个方法(如果Show Members右键单击Project菜单后已选择)
在IDE的其他地方(例如在测试类或非Java文件中),该Write Tests功能被禁用。
在Diffblue Cover为您的项目编写测试之后,它们将自动集成到您的测试套件中。Diffblue Cover创建的测试使用JUnit测试框架,因此junit包含在的CoreBanking项目依赖项中pom.xml。
在项目浏览器中,从CoreBanking-> src-> test-> java-> io.diffblue.corebanking-> ->中选择新类AccountTest,然后右键单击并选择Run 'AccountTest'
。
在本文中,我们将显示输入源和Cover生成的各种复杂性代码的测试,并附有详细的叙述,以帮助您进一步了解Cover生成的测试。
这是一个带有简单getter的Spring Service源代码的简单示例。DCover可以通过内联写一个春天开机测试的服务提供商,吸气Arrange,Act和Assert。
import org.springframework.stereotype.Service;
@Service
public class SimpleService
{
public String getValue() {
return "a really simple service";
}
}
@SpringBootTest
@RunWith(org.springframework.test.context.junit4.SpringRunner.class)
public class SimpleServiceDiffblueTest {
@Autowired
private SimpleService simpleService;
@Test
public void testGetValue() {
// Arrange, Act and Assert
assertEquals("a really simple service", this.simpleService.getValue());
}
}
此类包含两个方法,用于从Amazon S3存储桶上传文件和从Amazon S3存储桶下载文件。由于Amazon S3存储桶是一种云存储机制,因此此类/方法的测试需要依赖项注入。downloadFileFromBucket通过声明所需的S3Object和使用该方法下载的S3Object,DCover可以模拟这些类型的依赖关系并测试方法。
@Service
public class AmazonService {
@Autowired
private AmazonS3 s3client;
public PutObjectResult uploadFileToBucket(String bucketName, String key, File file) {
return s3client.putObject(bucketName, key, file);
}
public S3Object downloadFileFromBucket(String bucketName, String key) {
return s3client.getObject(bucketName, key);
}
}
@SpringBootTest
public class AmazonServiceDiffblueTest {
@MockBean
private AmazonS3Client amazonS3Client;
@Autowired
private AmazonService amazonService;
@Test
public void testUploadFileToBucket() {
// Arrange
PutObjectResult putObjectResult = new PutObjectResult();
putObjectResult.setContentMd5("file-hash");
when(this.amazonS3Client.putObject(or(isA(String.class), isNull()), or(isA(String.class), isNull()),
or(isA(File.class), isNull()))).thenReturn(putObjectResult);
// Act and Assert
assertSame(putObjectResult, this.amazonService.uploadFileToBucket("foo", "foo",
Paths.get(System.getProperty("java.io.tmpdir"), "test.txt").toFile()));
}
@Test
public void testDownloadFileFromBucket() throws UnsupportedEncodingException {
// Arrange
StringInputStream objectContent = new StringInputStream("file-name");
S3Object s3Object = new S3Object();
s3Object.setObjectContent(objectContent);
when(this.amazonS3Client.getObject(or(isA(String.class), isNull()), or(isA(String.class), isNull())))
.thenReturn(s3Object);
// Act and Assert
assertSame(s3Object, this.amazonService.downloadFileFromBucket("foo", "foo"));
}
}
本示例以其他格式返回时间。DCover编写一个测试以声明不依赖于操作系统或本地时区的日期和时间。
public class TimeInAliceWonderland {
private static final String DODO_DATETIME_FORMAT = "ss:mm:HH dd-MMM-yyyy";
public static String reformatDodoDateTime(Date humanDate) {
Map<String, DateFormat> dateFormatMap = new HashMap<>();
dateFormatMap.put(DODO_DATETIME_FORMAT, new SimpleDateFormat(DODO_DATETIME_FORMAT));
return dateFormatMap.get(DODO_DATETIME_FORMAT).format(humanDate);
}
}
@Test
public void testReformatDodoDateTime() {
LocalDateTime atStartOfDayResult = LocalDate.of(1970, 1, 1).atStartOfDay();
assertEquals("00:00:00 01-Jan-1970", TimeInAliceWonderland
.reformatDodoDateTime(
Date.from(atStartOfDayResult.atZone(ZoneId.systemDefault()).toInstant())));
}
在此示例中,DCover编写了两个测试以覆盖通过条件的每个路径-一个将余额加10并断言新余额应为20的测试,以及另一个关闭帐户的测试。
public class Account {
private final long accountNumber;
private final Client client;
private long currentBalance;
private String accountName;
private AccountState accountState;
public Account(final long accountNumber, final Client client, final long amount) {
this.accountNumber = accountNumber;
this.client = client;
currentBalance = amount;
accountName = "Current";
accountState = AccountState.OPEN;
}
public long getCurrentBalance() {
return currentBalance;
}
public void addToBalance(final long amount) throws AccountException {
if (getAccountState() != AccountState.OPEN) {
throw new AccountException("Cannot add to balance, account is closed.");
}
currentBalance += amount;
}
4.2 Diffblue Cover产生的测试
@Test
public void testAddToBalance() throws AccountException {
// Arrange
Account account = new Account(1234567890L, new Client("Carlos Welch"), 10L);
// Act
account.addToBalance(10L);
// Assert
assertEquals(20L, account.getCurrentBalance());
}
此示例代码具有3个分支-DCover覆盖了100%的分支,并使用现有的枚举值针对三种情况创建了三个测试。
public class VirtualSnackCupboard {
public static Snack whatCanISnackNow(int oClock) {
if (oClock == 10) {
return Snack.CHOCOLATE;
} else if (oClock == 15) {
return Snack.CAKES;
} else {
return Snack.VEGGIE;
}
}
enum Snack {
VEGGIE, CHOCOLATE, CAKES}
}
public void testPickSnack() {
assertEquals(VirtualSnackCupboard.Snack.CHOCOLATE, VirtualSnackCupboard.whatCanISnackNow(10));
assertEquals(VirtualSnackCupboard.Snack.CAKES, VirtualSnackCupboard.whatCanISnackNow(15));
assertEquals(VirtualSnackCupboard.Snack.VEGGIE, VirtualSnackCupboard.whatCanISnackNow(0));
可以看出,Diffblue Cover可以针对多种代码场景生成测试-我们鼓励您尝试Cover Cover CLI和Cover IntelliJ插件,以了解更多信息。
正如Diffblue首席执行官Mathew Lodge在一次采访中指出的那样,具有讽刺意味的是,鉴于我们如何使用AI来自动化和颠覆零售,旅行等许多其他行业,软件行业拥抱Al改善软件开发有多晚,运输,制造等。
Lodge说,Diffblue的研究人员利用了AlphaGo的机器学习策略,AlphaGo是Alphabet耔 公司DeepMind的软件程序,击败了Go的世界冠军。
当公司开始使用Java解决方案(迄今为止,这是全球2000年最受欢迎的语言,
公司在生产力工具上投入大量资金)时,其技术也可以用于对大多数编程语言(例如Python, JavaScript和C#)进行自动化测试。等等。
高盛(年度IT预算大于许多国家的GDP)是首批推出Diffblue解决方案的客户。
在一个具有重要后端系统的模块上 使用Diffblue的Al,高盛能够在不到24小时的时间内将现有的单元测试覆盖率从36%扩展到72%,这一壮举如果需要手动完成,将需要超过八天的开发时间。节省开发人员时间?90%。
Lodge认为系统变得如此复杂和庞大,以至于软件供应链的大部分构建,交付和维护工作,都比机器要好于人工。
从这个角度来看,他与Tyler Jewell-起加入, Tyler Jewell是一-位投资人,他撰写了- -些有关开发人员工具的最佳分析。
根据Jewell的说法:
由于工具和编程语言的碎片化,API的泛滥,微服务以及将大数据,分析,ML和反应性用户体验分层到项目中,软件系统变得更加复杂。
随着复杂性的增加,持续交付缩短了反馈循环,同时为开发人员提供了每次更改的更深入的见解。
与人相比,机器具有更好的装备,可以根据持续的反馈采取行动,并建议对极其复杂的系统
进行更改。
正如Jewell继续所说的那样,“数字服务的需求已经超过 了构建它们的工程师的供应,为可以提高开发人员生产力的供应商创造了机会。”
机器人交响曲并非只有Diffblue将此视为巨大的市场机会。在新出现的DevOps趋势的推动下,开发人员,运营和安全解决方案越来越多地转向预生产阶段,
并进一步移交给在编排之前构建模块的开发人员手中(例如,请参见Cyral的安全性, Vercel适用于JavaScript和React前端框架,Diffblue适用于单元测试自动化。
这种更大的变化与行业在数字化转型和云原生的新世界中对容器(通常是云)的采用相一致。当然,许多全球SaaS_上市公司在全球大流行中报告了惊人的季度收益和增长,这表明该类别的赢家将来会是什么样。
如今,SaaS 云公共市场EV /未来12个月收入中位数的比率达到惊人的15倍。2020年全球信息技术产业将达到5.2万亿美元,其中624B美元是软件。开发人员推动了软件市场份额的不断增长。
自主软件开发将是计算未来的重要组成部分。
Diffblue仅仅是 软件产业AI中断的开始。