为 JUnit 4/5 创建注释以在测试中初始化和注入对象
Creating an annotation for JUnit 4/5 to initialize and inject an object in tests
我正在为 Kafka 开发一个测试库,Kafkaesque。该库允许您使用流畅而优雅的 (?!) API 为 Kafka 开发集成测试。现在,我开发了 Spring Kafka 的版本。
每次测试都需要初始化库:
@Test
void consumeShouldConsumeMessagesProducesFromOutsideProducer() {
kafkaTemplate.sendDefault(1, "data1");
kafkaTemplate.sendDefault(2, "data2");
new SpringKafkaesque(broker)
.<Integer, String>consume()
.fromTopic(CONSUMER_TEST_TOPIC)
.waitingAtMost(1L, TimeUnit.SECONDS)
.waitingEmptyPolls(5, 100L, TimeUnit.MILLISECONDS)
.withDeserializers(new IntegerDeserializer(), new StringDeserializer())
.expecting()
.havingRecordsSize(2)
.assertingThatPayloads(Matchers.containsInAnyOrder("data1", "data2"))
.andCloseConsumer();
}
我不想手动初始化 SpringKafkaesque
对象,而是想创建一个对我来说很神奇的注释。类似于 Spring Kafka 的 @EmbeddedKafka
注释。
@SpringBootTest(classes = {TestConfiguration.class})
@Kafkaesque(
topics = {SpringKafkaesqueTest.CONSUMER_TEST_TOPIC, SpringKafkaesqueTest.PRODUCER_TEST_TOPIC})
class SpringKafkaesqueTest {
@Autowired
private Kafkaesque kafkaesque;
@Test
void consumeShouldConsumeMessagesProducesFromOutsideProducer() {
kafkaTemplate.sendDefault(1, "data1");
kafkaTemplate.sendDefault(2, "data2");
kafkaesque
.<Integer, String>consume()
.fromTopic(CONSUMER_TEST_TOPIC)
.waitingAtMost(1L, TimeUnit.SECONDS)
.waitingEmptyPolls(5, 100L, TimeUnit.MILLISECONDS)
.withDeserializers(new IntegerDeserializer(), new StringDeserializer())
.expecting()
.havingRecordsSize(2)
.assertingThatPayloads(Matchers.containsInAnyOrder("data1", "data2"))
.andCloseConsumer();
}
可能吗?有什么建议吗?
JUnit 4
一种可能的解决方案是使用反射创建自定义注释处理。你可以用 @Rule
获取测试方法名称,例如:
public class CustomAnnotationTest {
private SpringKafkaesque kafkaesqueInstance;
@Rule
public TestName testName = new TestName();
@Before
public void init() {
Method method = null;
try {
method = this.getClass().getMethod(testName.getMethodName());
} catch (Exception ex) {
// handle exceptions
}
if (method.isAnnotationPresent(EmbeddedKafka.class)) {
// Init your SpringKafkaesque instance here
// kafkaesqueInstance = new SpringKafkaesque(broker)
//
}
}
@EmbeddedKafka
@Test
public void testCustomAnnotated() {
// your test here
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface EmbeddedKafka {
}
}
您需要将此实例存储在 class-level 变量中。对于没有 @EmbeddedKafka
注释的方法,此变量将为 null
.
JUnit 5
对于 JUnit 5,您可以考虑使用 ParameterResolver
的参数注入。首先,你需要实现这个接口:
public class KafkaesqueResolver implements ParameterResolver {
@Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
return parameterContext.getParameter().getType() == SpringKafkaesque.class;
}
@Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
// Create an instance of SpringKafkaesque here and return it
return new SpringKafkaesque();
}
}
接下来,将 @ExtendWith(KafkaesqueResolver.class)
注释添加到您的测试 class,并向您的测试方法添加一个参数,其中您需要 SpringKafkaesque
:
的实例
@ExtendWith(KafkaesqueResolver.class)
public class ParamInjectionTest {
@Test
public void testNoParams() {
// nothing to inject
}
@Test
public void testWithParam(SpringKafkaesque instance) {
// do what you need with your instance
}
}
在这种情况下不需要自定义注释。
我正在为 Kafka 开发一个测试库,Kafkaesque。该库允许您使用流畅而优雅的 (?!) API 为 Kafka 开发集成测试。现在,我开发了 Spring Kafka 的版本。
每次测试都需要初始化库:
@Test
void consumeShouldConsumeMessagesProducesFromOutsideProducer() {
kafkaTemplate.sendDefault(1, "data1");
kafkaTemplate.sendDefault(2, "data2");
new SpringKafkaesque(broker)
.<Integer, String>consume()
.fromTopic(CONSUMER_TEST_TOPIC)
.waitingAtMost(1L, TimeUnit.SECONDS)
.waitingEmptyPolls(5, 100L, TimeUnit.MILLISECONDS)
.withDeserializers(new IntegerDeserializer(), new StringDeserializer())
.expecting()
.havingRecordsSize(2)
.assertingThatPayloads(Matchers.containsInAnyOrder("data1", "data2"))
.andCloseConsumer();
}
我不想手动初始化 SpringKafkaesque
对象,而是想创建一个对我来说很神奇的注释。类似于 Spring Kafka 的 @EmbeddedKafka
注释。
@SpringBootTest(classes = {TestConfiguration.class})
@Kafkaesque(
topics = {SpringKafkaesqueTest.CONSUMER_TEST_TOPIC, SpringKafkaesqueTest.PRODUCER_TEST_TOPIC})
class SpringKafkaesqueTest {
@Autowired
private Kafkaesque kafkaesque;
@Test
void consumeShouldConsumeMessagesProducesFromOutsideProducer() {
kafkaTemplate.sendDefault(1, "data1");
kafkaTemplate.sendDefault(2, "data2");
kafkaesque
.<Integer, String>consume()
.fromTopic(CONSUMER_TEST_TOPIC)
.waitingAtMost(1L, TimeUnit.SECONDS)
.waitingEmptyPolls(5, 100L, TimeUnit.MILLISECONDS)
.withDeserializers(new IntegerDeserializer(), new StringDeserializer())
.expecting()
.havingRecordsSize(2)
.assertingThatPayloads(Matchers.containsInAnyOrder("data1", "data2"))
.andCloseConsumer();
}
可能吗?有什么建议吗?
JUnit 4
一种可能的解决方案是使用反射创建自定义注释处理。你可以用 @Rule
获取测试方法名称,例如:
public class CustomAnnotationTest {
private SpringKafkaesque kafkaesqueInstance;
@Rule
public TestName testName = new TestName();
@Before
public void init() {
Method method = null;
try {
method = this.getClass().getMethod(testName.getMethodName());
} catch (Exception ex) {
// handle exceptions
}
if (method.isAnnotationPresent(EmbeddedKafka.class)) {
// Init your SpringKafkaesque instance here
// kafkaesqueInstance = new SpringKafkaesque(broker)
//
}
}
@EmbeddedKafka
@Test
public void testCustomAnnotated() {
// your test here
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface EmbeddedKafka {
}
}
您需要将此实例存储在 class-level 变量中。对于没有 @EmbeddedKafka
注释的方法,此变量将为 null
.
JUnit 5
对于 JUnit 5,您可以考虑使用 ParameterResolver
的参数注入。首先,你需要实现这个接口:
public class KafkaesqueResolver implements ParameterResolver {
@Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
return parameterContext.getParameter().getType() == SpringKafkaesque.class;
}
@Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
// Create an instance of SpringKafkaesque here and return it
return new SpringKafkaesque();
}
}
接下来,将 @ExtendWith(KafkaesqueResolver.class)
注释添加到您的测试 class,并向您的测试方法添加一个参数,其中您需要 SpringKafkaesque
:
@ExtendWith(KafkaesqueResolver.class)
public class ParamInjectionTest {
@Test
public void testNoParams() {
// nothing to inject
}
@Test
public void testWithParam(SpringKafkaesque instance) {
// do what you need with your instance
}
}
在这种情况下不需要自定义注释。