关注我带你了解科技领域最新的技术与产品
智能 BDD 是实现 BDD 最有效的方法。首先使用最佳实践编写代码,然后生成交互式文档。
Smart BDD是实施行为驱动开发(BDD)最高效的方法。传统的框架需要先编写静态的功能文件,然后再编写代码。
使用Smart BDD,你首先根据最佳实践编写代码,然后生成以下内容:
交互式HTML功能文件,用作文档用于更好地记录产品的图表该框架的目的是主要促进生产力!
作为起点,我将展示如何轻松将现有的测试升级为使用Smart BDD。
集成测试框架,如Spring集成测试非常强大和有用,如果能从中生成人类可读的文档和图表,将会更上一层楼!
你是否想过阅读不存在的文档或查看下游调用的图表?
这是一个非侵入性的框架,将丰富和改进你的测试,并促进最佳实践。
下面是代码生成的文档示例:这是一个简单的REST服务,用于获取一本书。
获取书籍的Smart BDD示例
请注意,Smart BDD是一个以代码优先为导向的测试框架,不仅适用于Spring,但本文重点阐述了一个使用案例和其带来的好处。
假设你现有的Spring集成测试看起来像这样:
Java
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BookControllerIT {
// 省略设置...
@Order(0)
@Test
public void getBookBy13DigitIsbn_returnsTheCorrectBook() {
whenGetBookByIsbnIsCalledWith(VALID_13_DIGIT_ISBN_FOR_BOOK_1);
thenTheResponseIsEqualTo(BOOK_1);
}
public void whenGetBookByIsbnIsCalledWith(String isbn) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(singletonList(MediaType.APPLICATION_JSON));
response = template.getForEntity("/book/" + isbn, String.class, headers);
}
// 省略辅助类...
}
这已经足够测试你的书店应用程序了,但我们可以将其提升到一个更高的水平。
从代码中生成文档并丰富你的测试非常容易:
只需在现有代码中添加@ExtendWith(SmartReport.class)以使用Smart BDD为了进一步从图表中受益,请看下面的示例:Java
@ExtendWith(SmartReport.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BookControllerIT {
// 省略设置...
@Overridepublic void doc() {
featureNotes("Working progress for example of usage Smart BDD");
}
@BeforeEach
void setupUml() {
sequenceDiagram()
.addActor("User")
.addParticipant("BookStore")
.addParticipant("ISBNdb");
}
@Order(0)@Test
public void getBookBy13DigitIsbn_returnsTheCorrectBook() {
whenGetBookByIsbnIsCalledWith(VALID_13_DIGIT_ISBN_FOR_BOOK_1);
thenTheResponseIsEqualTo(BOOK_1);
}
public void whenGetBookByIsbnIsCalledWith(String isbn) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(singletonList(MediaType.APPLICATION_JSON));
sequenceDiagram().add(aMessage().from("User").to("BookStore").text("/book/" + isbn));
response = template.getForEntity("/book/" + isbn, String.class, headers);
List<ServeEvent> allServeEvents = getAllServeEvents();allServeEvents.forEach(event -> {
sequenceDiagram().add(aMessage().from("BookStore").to("ISBNdb").text(event.getRequest().getUrl()));
sequenceDiagram().add(aMessage().from("ISBNdb").to("BookStore").text(
event.getResponse().getBodyAsString() + " [" + event.getResponse().getStatus() + "]"));
});
sequenceDiagram().add(aMessage().from("BookStore").to("User").text(response.getBody() + " [" + response.getStatusCode().value() + "]"));40}
private void thenTheResponseIsEqualTo(IsbnBook book) {
assertThat(bookFromJson(response.getBody())).isEqualTo(book);
}
// 省略辅助类...
}
使用指南首先,Smart BDD使用JUnit5,这是Smart BDD的唯一依赖。
注意:HTML文件只是结果的可视化呈现。
创建文档所需的所有工作都已完成!它通过将源代码进行标记化来实现。whenGetBookByIsbnIsCalledWith(VALID_13_DIGIT_ISBN_FOR_BOOK_1);会转换为"When get book by isbn is called with VALID_13_DIGIT_ISBN_FOR_BOOK_1"。它使用强大且可扩展的JUnit 5。它甚至支持重新运行测试。
其次,我们可以添加注释和图表。在上面的示例中,我们使用了一个Diagram/UML DSL来生成图表。
由于我们使用了WireMock,我们拥有捕获请求和响应所需的一切。捕获下游调用作为文档和了解服务工作方式的极好方法。
注意:
Java1List<ServeEvent> allServeEvents = getAllServeEvents();
上述代码是一种捕获WireMock事件的方法;您可以自由选择任何模拟框架。Smart BDD仅要求使用JUnit 5。
allServeEvents.forEach(event -> { sequenceDiagram().add(aMessage().from("BookStore").to("ISBNdb").text(event.getRequest().getUrl())); sequenceDiagram().add(aMessage().from("ISBNdb").to("BookStore").text( event.getResponse().getBodyAsString()+" ["+event.getResponse().getStatus()+"]")); }); sequenceDiagram().add(aMessage().from("BookStore").to("User").text(response.getBody()+" ["+response.getStatusCode().value()+"]"));
上述代码是用于图表/UML的DSL。它使用了Mermaid。正如您所见,这是一个包装器,用于创建序列图。这部分仍在开发中,在未来的版本中将支持渲染Mermaid支持的所有图表。
@Override public void doc() {
featureNotes("Working progress for example of usage Smart BDD"); }
上述代码生成功能注释。由于Smart BDD仍在开发中,选择了覆盖一个方法的方式,实际上也可以使用注解,例如@doc。您还可以在这里添加图表。
由于添加Smart BDD非常简单,我想向您介绍升级Spring集成测试的不那么明显的好处。
让我们来看一下业务逻辑。显然,您可以使用构建器或任何您喜欢的代码风格,我选择了以下样式,因为它很容易实现。
@Test public void getBookBy10DigitIsbnThatIsConvertedTo13DigitIsbn_returnsTheCorrectBookBasedOn DigitIsbn() { whenGetBookByIsbnIsCalledWith(VALID_10_DIGIT_ISBN_FOR_BOOK_1); thenTheResponseIsEqualTo(BOOK_1);
}
这生成了以下内容,它是上面图表的副本,所以我们可以并排查看。
获取图书智能BDD示例
请注意,阅读文档比代码要容易得多。想象一下,如果我们有一个向下游的REST调用到一个ISBN验证服务,那么在顺序图中这将变得很明显。
还要注意,编写像这样的高级测试是一种良好的实践。另一种选择是:
Java1@Test2public void getBookBy13DigitIsbn_returnsTheCorrectBook() {3final IsbnBook book = new IsbnBook(VALID_13_DIGIT_ISBN_FOR_BOOK_1, "book 1 title", singletonList("book 1 author"));4stubFor(get(urlEqualTo("/isbn-db/"+VALID_13_DIGIT_ISBN_FOR_BOOK_1))5.withPort(PORT)6.willReturn(aResponse()7.withHeader("Content-Type","application/json")8.withBody(bookAsString(book))));910HttpHeaders headers = new HttpHeaders();11headers.setAccept(singletonList(MediaType.APPLICATION_JSON));12
13ResponseEntity<String> response=template.getForEntity("/book/"+VALID_13_DIGIT_ISBN_FOR_BOOK_1, String.class, headers);14assertThat(bookFromJson(response.getBody())).isEqualTo(book);15}
我经常见到以上的代码。该框架最初的主要目标实际上是促进和使用最佳实践:
表达待测项的意图重用代码以保持文档一致。一旦您找到使用简单方法的限制,自然的进展是使用构建器。这实际上促进了一致的测试和文档。请注意上面那个大方法,它可以完成所有工作:
很难看出测试的意图。我们不必要地暴露了实现细节。这不容易维护。重复的测试最终会有重复的代码。这将导致覆盖率降低,因为添加新测试和维护现有测试的工作量很大。注意:当您使用构建器时,情况变得有趣起来:
Java1@Test2public void getBookUsingIsbn10() {3given(theIsbnDbContains().anEntry(forAnIsbn(ISBN_13_DIGITS).thatWillReturn(aDefaultIsbnBook().withIsbn(ISBN_13_DIGITS))));4when(aUserRequestsABook().withIsbn(ISBN_10_DIGITS));5then(theResponseContains(aDefaultIsbnBook().withIsbn(ISBN_13_DIGITS)));6}
上面是将构建器传递给给定/当/那么方法的原型。Smart BDD的一个未来功能可能是将构建器视为操作,然后:

将这些操作并行/异步执行以提高性能执行突变测试:例如,运行给定操作的0到n次更改构建器的值您可以指定如何处理空字符串或边缘情况。框架会为您注入所有组合计时这些操作以识别瓶颈等等...上面是智能测试的一个示例,如果您愿意,可以聪明地使用它。
其中的缺点是代码更复杂,因此在第一次编写时可能需要更长的时间,而且可能更难维护。构建器在您有少量端点和大量需求和/或状态时发挥最佳作用。
对于Spring应用程序来说,通过SpringBootTest(或等效)进行测试非常有效,但可视性却不足。可见性和透明度对于协作和反馈非常重要。
要开始开发一个功能,您必须清楚要求,实现这个目标的好方法是编写功能测试或拥有良好的文档。幸运的是,我们都会得到。这是一个关于可见性、透明度和清晰度的完美起点。三位好友会议是一种常见的实践,开发人员、产品所有者等业务人员和QA工程师讨论需求。这样的会议可以添加到您对工作项何时可以开始的定义中。根据您的流程和需求,这对您的项目非常有益处。
完成工作并解决细微差别后(由测试/文档覆盖),您可以选择通过显示团队测试/文档来演示已完成的工作。请注意,这也可以是您定义完成的一部分。
向团队展示应确保高质量的功能、测试和文档。这些测试/文档可以被以下人员参考:
新开发人员业务人员支持团队的人员—当凌晨2点时,良好的文档将受到赞赏任何需要回顾某项功能如何工作的人员每个公司、团队、项目都是不同的-您可能不需要上述内容,但知道这是一个选择,使用Smart BDD比仅使用Spring集成测试更容易实现。
因此,出于这个原因和其他原因,人们使用BDD框架。事实上,首先编写功能需求以确保您正在实现正确的行为是一个非常好的主意。这也被称为“从外到内工作”:
首先编写功能需求然后是应用程序接口(在这种情况下为REST),然后是服务,最后是DB访问和/或下游调用。传统的BDD框架通常更复杂,提供的功能较少:
您将首先编写特性文件,然后是粘合层,最后是测试代码测试更多功能变得更难维护,并且功能变得不一致可能以不同的语言实施,通常导致质量不高我试图表达的是,Smart BDD促进了以最小的努力做正确的事情的理念。
接下来,我计划在生成的HTML中实现一些很棒的功能:
重新运行测试的按钮允许您更改测试参数的UI感谢GitHub上的Bodar,他做了一个与JUnit 4配合使用的类似项目。
我正在寻找更多的实际用途,并且我很愿意帮助任何人编写新的测试或将现有测试迁移到此框架。如果您有兴趣,请联系我-请查看我的GitHub个人资料以获取我的联系方式。如果您想要贡献,请访问这里。