1.概述

JUNIT 5.图书馆在其先前版本中提供了许多新功能。一个这样的特征是测试模板.简而言之,测试模板是JUnit 5的参数化和的强大泛化重复测试。

在本教程中,我们将学习如何使用JUnit 5创建测试模板。

2. Maven依赖项

让我们从添加依赖关系开始pom.xml.

我们需要添加主Junit 5junit-jupiter-engine依赖性:

<依赖>  org.junit.jupiter   JUNIT-JUPITER-ENGINE   5.7.0  

除此之外,我们还需要添加junit-jupiter-api依赖性:

<依赖>  org.junit.jupiter   JUnit-Jupitor-API   5.7.0  

同样,我们可以将必要的依赖项添加到build.gradle.文件:

testcompile组:'org.junit.jupitor',名称:'junit-jupiter-engine',版本:'5.7.0'testcompile组:'org.junit.jupiter',名称:'junit-jupiter-api',版本:'5.7.0'

3.问题陈述

在查看测试模板之前,让我们简要看看JUnit 5'参数化测试.参数化测试允许我们将不同的参数注入测试方法。结果,何时使用参数化测试,我们可以通过不同参数多次执行单个测试方法。

让我们假设我们现在想多次运行测试方法 - 不仅仅是在不同的参数中,还可以每次都在不同的调用上下文下。

换句话说,我们希望多次执行测试方法,每次调用都使用不同的配置组合如:

  • 使用不同的参数
  • 以不同的方式准备测试类实例—即,将不同的依赖项注入到测试实例中
  • 在不同的条件下运行测试,例如启用/禁用该环境的子集,如果环境是“QA.
  • 使用不同的生命周期回调行为运行 - 也许我们想在调用子集之前和之后设置和拆除数据库

在这种情况下,使用参数化测试可以快速证明有限。值得庆幸的是,JUnit 5以测试模板的形式为此方案提供了强大的解决方案。

4.测试模板

测试模板本身不是测试用例。相反,正如他们的名字所建议的那样,它们只是给定测试用例的模板。它们是参数化和重复测试的强大泛化。

为调用上下文提供程序提供给它们的每个调用上下文,调用测试模板。

现在让我们看一下测试模板的一个例子。如上所述,主要参与者是:

  • 测试目标方法
  • 测试模板方法
  • 使用模板方法注册的一个或多个调用上下文提供程序
  • 每个调用上下文提供者提供的一个或多个调用上下文

4.1。测试目标方法

对于这个例子,我们将使用简单useridgeneratorimpl.generate.方法作为我们的测试目标。

让我们定义useridgeneratorimpl.班级:

public class UserIdGeneratorImpl implements UserIdGenerator {private boolean isFeatureEnabled;public UserIdGeneratorImpl(boolean isFeatureEnabled) {this。isFeatureEnabled = isFeatureEnabled;} public String generate(String firstName, String lastName) {String initialAndLastName = firstName。substring (0, 1) .concat(姓);返回isFeatureEnabled吗?印度枳.concat (initialAndLastName): initialAndLastName;}}

产生方法,即我们的测试目标,获取作为参数并生成用户ID。用户ID的格式因是否启用了特征开关而异。

让我们看看这个看起来如何:

当FirstName =“John”和LastName =“Smith”然后返回“JSMITH”时,返回给定的功能交换机将启用“John”和LastName =“史密斯”然后“Baeljsmith”返回“jsmith”时禁用“jsmith”。然后返回“baeljsmith”时启用了“jsmith”。然后返回“baeljsmith”

接下来,让我们编写测试模板方法。

4.2。测试模板方法

下面是我们的测试目标方法的测试模板useridgeneratorimpl.generate.

公共类useridgeneratorimplunittest {@testtemplate @extendwith(useridgeneratortestinvitchvocateContextprovider.class)whenUserIDRequested_thenuserIdisReturnedCincorCordFormat(UseridGenerator useridGenerator = new useridgeneratorimpl(testcase.isfeatureenabled());String amantyUserID = UserIDGenerator.generate(testcase.getfirstname(),testcase.getlastname());assertthat(alutyuserid).isequalto(testcase.getexpecteduserid());}}

让我们仔细看看测试模板方法。

首先,我们通过将其与JUNIT 5标记来创建我们的测试模板方法@TestTemplate注解

再往下,我们注册了一个上下文提供者useridgeneratortestinvocateContextProvider,使用@extendwith.注解.我们可以使用测试模板注册多个上下文提供程序。但是,出于此示例的目的,我们注册了一个提供商。

此外,模板方法接收了一个实例useridgeneratortestStast.作为一个参数。这只是输入的包装类以及测试用例的预期结果:

public class UserIdGeneratorTestCase {private boolean isFeatureEnabled;私人字符串firstName;私人字符串姓;私人字符串expectedUserId;//标准的setter和getter}

最后,我们调用测试目标方法并断言结果如预期的那样

现在,是时候定义调用上下文提供程序了

4.3。调用上下文提供者

我们需要注册至少一个TestTemplateInvocationContextProvider使用我们的测试模板。每个注册TestTemplateInvocationContextProvider提供了一个TestTemplateInvocationContext实例

以前,使用了@extendwith.注释,我们注册useridgeneratortestinvocateContextProvider.作为我们的调用提供者。

现在让我们来定义这个类:

公共类useridgeneratortestinvocationcontextprovider实现testtemplingInvocationContextProvider {// ...}

我们的调用背景实施TestTemplateInvocationContextProvider接口,有两种方法:

  • supportstesttemplate.
  • ProvideTestTemplateInVocateContexts.

让我们从实现supportstesttemplate.方法:

@Override公共布尔支持静坐(ExtensionContext ExtensionContext){返回true;}

的执行引擎调用supportstesttemplate.方法首先要验证提供程序是否适用于给定ExecutionContext..在本例中,我们只是返回真正的

现在,让我们实施ProvideTestTemplateInVocateContexts.方法:

@override公共流 ProvideTestTemplingInVocateContexts(ExtensionContext ExtensionContext){boolean括号isabled = false;布尔efferentEnabled = true;返回stream.of(featuredisabledcontext(新用户idgeneratorteststase(当用户名时,禁用给定的功能交换机,当用户名为John Smith时,EsterID为Jsmith),特色is,“John”,“smith”,“jsmith”)),featureenbabledContext(New UserIdgeneratortestCase(“)当用户名是John Smith时,授予特征开关然后生成userID是Baeljsmith“,FeateBelabled,”John“,”Smith“,”Baeljsmith“)));}

的目的是ProvideTestTemplateInVocateContexts.方法是提供一个TestTemplateInvocationContext实例。对于我们的示例,它返回两个实例,由方法提供featureDisabledContextfeatureEnabledContext.因此,我们的测试模板将运行两次。

接下来,让我们看看这两个TestTemplateInvocationContext由这些方法返回的实例。

4.4。调用语境实例

调用上下文是TestTemplateInvocationContext接口并实现以下方法:

  • getDisplayName.- 提供测试显示名称
  • getAdditionalExtensions- 返回调用上下文的其他扩展

让我们定义featureDisabledContext返回我们的第一个调用上下文实例的方法:

private testtemplingInvocateContext特色isableabledContext(useridgeneratortesteStext useridgeneratortestcase){return new testtemplateInvocationContext(){@override public string getdisplayname(int invocationIndex){return useridgeneratortests.getdisplayname();@override公共列表<扩展名> getadditionalextensions(){return aslist(新的generictypedparameterresolver(useridgeneratorteststuck),new beforeTestexecutioncallback(){@override public void beforeTestexecution(extensionContext ExtensionContext){system.out.println(“beforeTestexecutionCallback:禁用上下文”);}},新的之后executionCallback(){@override公共void后端estexecution(extensionContext ExtensionContext){system.out.println(“后续executionscallback:disabled上下文”);}});}};}

方法返回的调用上下文featureDisabledContext方法,延期我们注册的是:

  • GenerictypedParameterResolver.——一个参数解析器扩大
  • beforeTexecutionCallback.- 一个生命周期回调扩展,在测试执行之前立即运行
  • AfterTestExecutionCallback- 一个生命周期回调扩展,在测试执行后立即运行

但是,对于第二次调用背景,由此返回featureEnabledContext方法,让我们注册一个不同的扩展集(保持GenerictypedParameterResolver.):

private TestTemplateInvocationContext featureEnabledContext(UserIdGeneratorTestCase UserIdGeneratorTestCase) {return new TestTemplateInvocationContext() {@Override public String getDisplayName(int invocationIndex) {return UserIdGeneratorTestCase .getDisplayName();} @Override public List getAdditionalExtensions() {return asList(new GenericTypedParameterResolver(userIdGeneratorTestCase), new DisabledOnQAEnvironmentExtension(), new BeforeEachCallback() {@Override public void beforeEach(ExtensionContext ExtensionContext) {System.out。println(“BeforeEachCallback:启用上下文”);}}, new AfterEachCallback() {@Override public void afterEach(ExtensionContext ExtensionContext) {System.out。println(“AfterEachCallback:启用上下文”);}});}};}

对于第二个调用语境,我们注册的扩展是:

  • GenerictypedParameterResolver.- 参数解析器扩展
  • Disablaseonqaenvironmentextension.-如果环境属性(从application.properties.文件)是“QA.
  • 前家-在每个测试方法执行之前运行的生命周期回调扩展
  • AfterEachCallback- 一个生命周期回调扩展,在每个测试方法执行后运行

从上面的例子可以清楚地看到:

  • 在多个调用上下文下运行相同的测试方法
  • 每个调用上下文都使用自己的一组扩展,这些扩展位于其他调用上下文中的扩展中的数量和性质

结果,每次在完全不同的调用上下文下可以多次调用测试方法。并且通过注册多个上下文提供程序,我们可以提供更多附加的调用图层来运行测试。

5.结论

在本文中,我们研究JUnit 5的测试模板是如何强大的参数化和重复测试的泛化。

首先,我们研究了参数化测试的一些局限性。接下来,我们讨论了测试模板如何通过允许在每个调用的不同上下文下运行测试来克服限制。

最后,我们看了一个创建新测试模板的示例。我们分解了这个示例,以理解模板如何与调用上下文提供程序和调用上下文一起工作。

一如既往,本文中使用的示例的源代码可用在github上

通用底部

使用Spring 5和Spring Boot 2开始,通过学习的春天课程:

>>看看这个课程
评论在本文上关闭!