diff --git a/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java index 327cacb17e5c..8cae398efea1 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java @@ -56,6 +56,8 @@ * TransactionalTestExecutionListener} *
  • {@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener * SqlScriptsTestExecutionListener}
  • + *
  • {@link org.springframework.test.context.event.EventPublishingTestExecutionListener + * EventPublishingTestExecutionListener} (not registered by default)
  • * * * @author Sam Brannen diff --git a/spring-test/src/main/java/org/springframework/test/context/TestExecutionListeners.java b/spring-test/src/main/java/org/springframework/test/context/TestExecutionListeners.java index d1db5c75c912..1dcec5e8c0e9 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestExecutionListeners.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestExecutionListeners.java @@ -66,6 +66,7 @@ * @see org.springframework.test.context.support.DirtiesContextTestExecutionListener * @see org.springframework.test.context.transaction.TransactionalTestExecutionListener * @see org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener + * @see org.springframework.test.context.event.EventPublishingTestExecutionListener */ @AliasFor("value") Class[] listeners() default {}; diff --git a/spring-test/src/main/java/org/springframework/test/context/event/AfterTestClassEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/AfterTestClassEvent.java new file mode 100644 index 000000000000..c54f00e26fdc --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/AfterTestClassEvent.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; + +/** + * {@link TestContextEvent} published by {@link EventPublishingTestExecutionListener} when + * {@link org.springframework.test.context.TestExecutionListener#afterTestClass(TestContext)} is called. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.AfterTestClass + */ +@SuppressWarnings("serial") +public class AfterTestClassEvent extends TestContextEvent { + + public AfterTestClassEvent(TestContext source) { + super(source); + } +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/AfterTestExecutionEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/AfterTestExecutionEvent.java new file mode 100644 index 000000000000..b103bab17d54 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/AfterTestExecutionEvent.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; + +/** + * {@link TestContextEvent} published by {@link EventPublishingTestExecutionListener} when + * {@link org.springframework.test.context.TestExecutionListener#afterTestExecution(TestContext)} is called. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.AfterTestExecution + */ +@SuppressWarnings("serial") +public class AfterTestExecutionEvent extends TestContextEvent { + + public AfterTestExecutionEvent(TestContext source) { + super(source); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/AfterTestMethodEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/AfterTestMethodEvent.java new file mode 100644 index 000000000000..b44eada444fa --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/AfterTestMethodEvent.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; + +/** + * {@link TestContextEvent} published by {@link EventPublishingTestExecutionListener} when + * {@link org.springframework.test.context.TestExecutionListener#afterTestMethod(TestContext)} is called. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.AfterTestMethod + */ +@SuppressWarnings("serial") +public class AfterTestMethodEvent extends TestContextEvent { + + public AfterTestMethodEvent(TestContext source) { + super(source); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestClassEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestClassEvent.java new file mode 100644 index 000000000000..760af2a090cf --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestClassEvent.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; + +/** + * {@link TestContextEvent} published by {@link EventPublishingTestExecutionListener} when + * {@link org.springframework.test.context.TestExecutionListener#beforeTestClass(TestContext)} is called. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.BeforeTestClass + */ +@SuppressWarnings("serial") +public class BeforeTestClassEvent extends TestContextEvent { + + public BeforeTestClassEvent(TestContext source) { + super(source); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestExecutionEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestExecutionEvent.java new file mode 100644 index 000000000000..99907e063150 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestExecutionEvent.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; + +/** + * {@link TestContextEvent} published by {@link EventPublishingTestExecutionListener} when + * {@link org.springframework.test.context.TestExecutionListener#beforeTestExecution(TestContext)} is called. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.BeforeTestExecution + */ +@SuppressWarnings("serial") +public class BeforeTestExecutionEvent extends TestContextEvent { + + public BeforeTestExecutionEvent(TestContext source) { + super(source); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestMethodEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestMethodEvent.java new file mode 100644 index 000000000000..ab1c0ed972e2 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/BeforeTestMethodEvent.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; + +/** + * {@link TestContextEvent} published by {@link EventPublishingTestExecutionListener} when + * {@link org.springframework.test.context.TestExecutionListener#beforeTestMethod(TestContext)} is called. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.BeforeTestMethod + */ +@SuppressWarnings("serial") +public class BeforeTestMethodEvent extends TestContextEvent { + + public BeforeTestMethodEvent(TestContext source) { + super(source); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java new file mode 100644 index 000000000000..6d55db6bafcf --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; +import org.springframework.test.context.support.AbstractTestExecutionListener; + +/** + * {@link org.springframework.test.context.TestExecutionListener} that may be used to publish test life-cycle event to + * the Spring test {@link org.springframework.context.ApplicationContext}. + * + *

    These events may be consumed for various reasons, such as resetting {@em mock} beans or tracing test + * execution. Since these events may consumed as part of regular Spring beans, they can be shared among + * different test classes. + * + *

    This {@link org.springframework.test.context.TestExecutionListener} is not active by default. Test classes + * should be annotated using {@link org.springframework.test.context.TestExecutionListeners}, if they want to use it. + * Alternatively, it may be added to {@code spring.factories}, if needed. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.BeforeTestClass + * @see org.springframework.test.context.event.annotation.PrepareTestInstance + * @see org.springframework.test.context.event.annotation.BeforeTestMethod + * @see org.springframework.test.context.event.annotation.BeforeTestExecution + * @see org.springframework.test.context.event.annotation.AfterTestExecution + * @see org.springframework.test.context.event.annotation.AfterTestMethod + * @see org.springframework.test.context.event.annotation.AfterTestClass + */ +public class EventPublishingTestExecutionListener extends AbstractTestExecutionListener { + + @Override + public void beforeTestClass(TestContext testContext) { + testContext.getApplicationContext().publishEvent( + new BeforeTestClassEvent(testContext)); + } + + @Override + public void prepareTestInstance(TestContext testContext) { + testContext.getApplicationContext().publishEvent( + new PrepareTestInstanceEvent(testContext)); + } + + @Override + public void beforeTestMethod(TestContext testContext) { + testContext.getApplicationContext().publishEvent( + new BeforeTestMethodEvent(testContext)); + } + + @Override + public void beforeTestExecution(TestContext testContext) { + testContext.getApplicationContext().publishEvent( + new BeforeTestExecutionEvent(testContext)); + } + + @Override + public void afterTestExecution(TestContext testContext) { + testContext.getApplicationContext().publishEvent( + new AfterTestExecutionEvent(testContext)); + } + + @Override + public void afterTestMethod(TestContext testContext) { + testContext.getApplicationContext().publishEvent( + new AfterTestMethodEvent(testContext)); + } + + @Override + public void afterTestClass(TestContext testContext) { + testContext.getApplicationContext().publishEvent( + new AfterTestClassEvent(testContext)); + } +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/PrepareTestInstanceEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/PrepareTestInstanceEvent.java new file mode 100644 index 000000000000..5a26fb80008b --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/PrepareTestInstanceEvent.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.test.context.TestContext; + +/** + * {@link TestContextEvent} published by {@link EventPublishingTestExecutionListener} when + * {@link org.springframework.test.context.TestExecutionListener#prepareTestInstance(TestContext)} is called. + * + * @author Frank Scheffler + * @since 5.2 + * @see org.springframework.test.context.event.annotation.PrepareTestInstance + */ +@SuppressWarnings("serial") +public class PrepareTestInstanceEvent extends TestContextEvent { + + public PrepareTestInstanceEvent(TestContext source) { + super(source); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/TestContextEvent.java b/spring-test/src/main/java/org/springframework/test/context/event/TestContextEvent.java new file mode 100644 index 000000000000..20a3787b8942 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/TestContextEvent.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.springframework.context.ApplicationEvent; +import org.springframework.test.context.TestContext; + +/** + * Base class for events published by {@link EventPublishingTestExecutionListener}. + * + * @author Frank Scheffler + * @since 5.2 + */ +@SuppressWarnings("serial") +public abstract class TestContextEvent extends ApplicationEvent { + + public TestContextEvent(TestContext source) { + super(source); + } + + /* + * (non-Javadoc) + * + * @see java.util.EventObject#getSource() + */ + @Override + public TestContext getSource() { + return (TestContext) super.getSource(); + } +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestClass.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestClass.java new file mode 100644 index 000000000000..b4e7ddb6fcfc --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestClass.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event.annotation; + +import org.springframework.context.event.EventListener; +import org.springframework.test.context.event.AfterTestClassEvent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * {@link EventListener} annotation used to consume {@link AfterTestClassEvent}s published + * by {@link org.springframework.test.context.event.EventPublishingTestExecutionListener}. + * + *

    This annotation may be used on {@link EventListener}-compliant methods within the Spring test + * {@link org.springframework.context.ApplicationContext}, typically within + * {@link org.springframework.context.annotation.Configuration}s. A method annotated hereby will be + * called as part of the {@link org.springframework.test.context.TestExecutionListener#afterTestClass(org.springframework.test.context.TestContext)} + * life-cycle method. + * + *

    Make sure {@link org.springframework.test.context.event.EventPublishingTestExecutionListener} is enabled, + * for this annotation to have an effect, e.g. by annotation your test class with + * {@link org.springframework.test.context.TestExecutionListeners} accordingly. + * + * @author Frank Scheffler + * @since 5.2 + * @see AfterTestClassEvent + */ +@Documented +@Retention(RUNTIME) +@Target({METHOD, ANNOTATION_TYPE}) +@EventListener(AfterTestClassEvent.class) +public @interface AfterTestClass { +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestExecution.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestExecution.java new file mode 100644 index 000000000000..642699d70cd1 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestExecution.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event.annotation; + +import org.springframework.context.event.EventListener; +import org.springframework.test.context.event.AfterTestExecutionEvent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * {@link EventListener} annotation used to consume {@link AfterTestExecutionEvent}s published + * by {@link org.springframework.test.context.event.EventPublishingTestExecutionListener}. + * + *

    This annotation may be used on {@link EventListener}-compliant methods within the Spring test + * {@link org.springframework.context.ApplicationContext}, typically within + * {@link org.springframework.context.annotation.Configuration}s. A method annotated hereby will be + * called as part of the {@link org.springframework.test.context.TestExecutionListener#afterTestExecution(org.springframework.test.context.TestContext)} + * life-cycle method. + * + *

    Make sure {@link org.springframework.test.context.event.EventPublishingTestExecutionListener} is enabled, + * for this annotation to have an effect, e.g. by annotation your test class with + * {@link org.springframework.test.context.TestExecutionListeners} accordingly. + * + * @author Frank Scheffler + * @since 5.2 + * @see AfterTestExecutionEvent + */ +@Documented +@Retention(RUNTIME) +@Target({METHOD, ANNOTATION_TYPE}) +@EventListener(AfterTestExecutionEvent.class) +public @interface AfterTestExecution { +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestMethod.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestMethod.java new file mode 100644 index 000000000000..89a6fc422cbb --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestMethod.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event.annotation; + +import org.springframework.context.event.EventListener; +import org.springframework.test.context.event.AfterTestMethodEvent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * {@link EventListener} annotation used to consume {@link AfterTestMethodEvent}s published + * by {@link org.springframework.test.context.event.EventPublishingTestExecutionListener}. + * + *

    This annotation may be used on {@link EventListener}-compliant methods within the Spring test + * {@link org.springframework.context.ApplicationContext}, typically within + * {@link org.springframework.context.annotation.Configuration}s. A method annotated hereby will be + * called as part of the {@link org.springframework.test.context.TestExecutionListener#afterTestMethod(org.springframework.test.context.TestContext)} + * life-cycle method. + * + *

    Make sure {@link org.springframework.test.context.event.EventPublishingTestExecutionListener} is enabled, + * for this annotation to have an effect, e.g. by annotation your test class with + * {@link org.springframework.test.context.TestExecutionListeners} accordingly. + * + * @author Frank Scheffler + * @since 5.2 + * @see AfterTestMethodEvent + */ +@Documented +@Retention(RUNTIME) +@Target({METHOD, ANNOTATION_TYPE}) +@EventListener(AfterTestMethodEvent.class) +public @interface AfterTestMethod { +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestClass.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestClass.java new file mode 100644 index 000000000000..29badc02c3ea --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestClass.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event.annotation; + +import org.springframework.context.event.EventListener; +import org.springframework.test.context.event.BeforeTestClassEvent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * {@link EventListener} annotation used to consume {@link BeforeTestClassEvent}s published + * by {@link org.springframework.test.context.event.EventPublishingTestExecutionListener}. + * + *

    This annotation may be used on {@link EventListener}-compliant methods within the Spring test + * {@link org.springframework.context.ApplicationContext}, typically within + * {@link org.springframework.context.annotation.Configuration}s. A method annotated hereby will be + * called as part of the {@link org.springframework.test.context.TestExecutionListener#beforeTestClass(org.springframework.test.context.TestContext)} + * life-cycle method. + * + *

    Make sure {@link org.springframework.test.context.event.EventPublishingTestExecutionListener} is enabled, + * for this annotation to have an effect, e.g. by annotation your test class with + * {@link org.springframework.test.context.TestExecutionListeners} accordingly. + * + * @author Frank Scheffler + * @since 5.2 + * @see BeforeTestClassEvent + */ +@Documented +@Retention(RUNTIME) +@Target({METHOD, ANNOTATION_TYPE}) +@EventListener(BeforeTestClassEvent.class) +public @interface BeforeTestClass { +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestExecution.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestExecution.java new file mode 100644 index 000000000000..b9fa796b57c3 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestExecution.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event.annotation; + +import org.springframework.context.event.EventListener; +import org.springframework.test.context.event.BeforeTestExecutionEvent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * {@link EventListener} annotation used to consume {@link BeforeTestExecutionEvent}s published + * by {@link org.springframework.test.context.event.EventPublishingTestExecutionListener}. + * + *

    This annotation may be used on {@link EventListener}-compliant methods within the Spring test + * {@link org.springframework.context.ApplicationContext}, typically within + * {@link org.springframework.context.annotation.Configuration}s. A method annotated hereby will be + * called as part of the {@link org.springframework.test.context.TestExecutionListener#beforeTestExecution(org.springframework.test.context.TestContext)} + * life-cycle method. + * + *

    Make sure {@link org.springframework.test.context.event.EventPublishingTestExecutionListener} is enabled, + * for this annotation to have an effect, e.g. by annotation your test class with + * {@link org.springframework.test.context.TestExecutionListeners} accordingly. + * + * @author Frank Scheffler + * @since 5.2 + * @see BeforeTestExecutionEvent + */ +@Documented +@Retention(RUNTIME) +@Target({METHOD, ANNOTATION_TYPE}) +@EventListener(BeforeTestExecutionEvent.class) +public @interface BeforeTestExecution { +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestMethod.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestMethod.java new file mode 100644 index 000000000000..d7a7483ffc28 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestMethod.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event.annotation; + +import org.springframework.context.event.EventListener; +import org.springframework.test.context.event.BeforeTestMethodEvent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * {@link EventListener} annotation used to consume {@link BeforeTestMethodEvent}s published + * by {@link org.springframework.test.context.event.EventPublishingTestExecutionListener}. + * + *

    This annotation may be used on {@link EventListener}-compliant methods within the Spring test + * {@link org.springframework.context.ApplicationContext}, typically within + * {@link org.springframework.context.annotation.Configuration}s. A method annotated hereby will be + * called as part of the {@link org.springframework.test.context.TestExecutionListener#beforeTestMethod(org.springframework.test.context.TestContext)} + * life-cycle method. + * + *

    Make sure {@link org.springframework.test.context.event.EventPublishingTestExecutionListener} is enabled, + * for this annotation to have an effect, e.g. by annotation your test class with + * {@link org.springframework.test.context.TestExecutionListeners} accordingly. + * + * @author Frank Scheffler + * @since 5.2 + * @see BeforeTestMethodEvent + */ +@Documented +@Retention(RUNTIME) +@Target({METHOD, ANNOTATION_TYPE}) +@EventListener(BeforeTestMethodEvent.class) +public @interface BeforeTestMethod { +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/PrepareTestInstance.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/PrepareTestInstance.java new file mode 100644 index 000000000000..e410c58552ef --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/PrepareTestInstance.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event.annotation; + +import org.springframework.context.event.EventListener; +import org.springframework.test.context.event.PrepareTestInstanceEvent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * {@link EventListener} annotation used to consume {@link PrepareTestInstanceEvent}s published + * by {@link org.springframework.test.context.event.EventPublishingTestExecutionListener}. + * + *

    This annotation may be used on {@link EventListener}-compliant methods within the Spring test + * {@link org.springframework.context.ApplicationContext}, typically within + * {@link org.springframework.context.annotation.Configuration}s. A method annotated hereby will be + * called as part of the {@link org.springframework.test.context.TestExecutionListener#prepareTestInstance(org.springframework.test.context.TestContext)} + * life-cycle method. + * + *

    Make sure {@link org.springframework.test.context.event.EventPublishingTestExecutionListener} is enabled, + * for this annotation to have an effect, e.g. by annotation your test class with + * {@link org.springframework.test.context.TestExecutionListeners} accordingly. + * + * @author Frank Scheffler + * @since 5.2 + * @see PrepareTestInstanceEvent + */ +@Documented +@Retention(RUNTIME) +@Target({METHOD, ANNOTATION_TYPE}) +@EventListener(PrepareTestInstanceEvent.class) +public @interface PrepareTestInstance { +} diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/package-info.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/package-info.java new file mode 100644 index 000000000000..efc10e414a7f --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/package-info.java @@ -0,0 +1,4 @@ +/** + * Test event annotations for the Spring TestContext Framework. + */ +package org.springframework.test.context.event.annotation; \ No newline at end of file diff --git a/spring-test/src/main/java/org/springframework/test/context/event/package-info.java b/spring-test/src/main/java/org/springframework/test/context/event/package-info.java new file mode 100644 index 000000000000..3d8677b979a9 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/event/package-info.java @@ -0,0 +1,4 @@ +/** + * Test event support classes for the Spring TestContext Framework. + */ +package org.springframework.test.context.event; \ No newline at end of file diff --git a/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java new file mode 100644 index 000000000000..910e107c25a4 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java @@ -0,0 +1,170 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import java.lang.reflect.Method; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContext; +import org.springframework.test.context.TestContextManager; +import org.springframework.test.context.TestExecutionListener; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.event.annotation.*; +import org.springframework.util.ReflectionUtils; + +import static org.mockito.BDDMockito.*; + +/** + * Integration test for {@link EventPublishingTestExecutionListener} and + * accompanying {@link TestContextEvent} annotations. + * + * @author Frank Scheffler + * @since 5.2 + */ +public class EventPublishingTestExecutionListenerIntegrationTests { + + private TestContextManager testContextManager; + private TestContext testContext; + private TestExecutionListener trigger; + private Object testInstance; + private Method testMethod; + + @Configuration + static class EventCaptureConfiguration { + @Bean + public TestExecutionListener trigger() { + return mock(TestExecutionListener.class); + } + + @BeforeTestClass + public void beforeTestClass(BeforeTestClassEvent e) throws Exception { + trigger().beforeTestClass(e.getSource()); + } + + @PrepareTestInstance + public void prepareTestInstance(PrepareTestInstanceEvent e) throws Exception { + trigger().prepareTestInstance(e.getSource()); + } + + + @BeforeTestMethod + public void beforeTestMethod(BeforeTestMethodEvent e) throws Exception { + trigger().beforeTestMethod(e.getSource()); + } + + @BeforeTestExecution + public void beforeTestExecutiob(BeforeTestExecutionEvent e) throws Exception { + trigger().beforeTestExecution(e.getSource()); + } + + @AfterTestExecution + public void afterTestExecution(AfterTestExecutionEvent e) throws Exception { + trigger().afterTestExecution(e.getSource()); + } + + @AfterTestMethod + public void afterTestMethod(AfterTestMethodEvent e) throws Exception { + trigger().afterTestMethod(e.getSource()); + } + + @AfterTestClass + public void afterTestClass(AfterTestClassEvent e) throws Exception { + trigger().afterTestClass(e.getSource()); + } + + } + + @ContextConfiguration(classes = EventCaptureConfiguration.class) + @TestExecutionListeners(EventPublishingTestExecutionListener.class) + static class EmptyTestCase { + + /** + * Serves as dummy test method. + */ + @SuppressWarnings("PMD.UncommentedEmptyMethodBody") + public void dummyTestMethod() { + } + } + + static class TestContextExposingTestContextManager extends TestContextManager { + public TestContextExposingTestContextManager() { + super(EmptyTestCase.class); + } + + public TestContext getProtectedTestContext() { + return getTestContext(); + } + } + + @Before + public void initialize() { + TestContextExposingTestContextManager tcm = new TestContextExposingTestContextManager(); + testContextManager = tcm; + testContext = tcm.getProtectedTestContext(); + trigger = testContext.getApplicationContext().getBean(EventCaptureConfiguration.class).trigger(); + // reset because mock is a cached context bean + reset(trigger); + testInstance = new EmptyTestCase(); + testMethod = ReflectionUtils.findMethod(EmptyTestCase.class, "dummyMethod"); + } + + @Test + public void beforeTestClassAnnotation() throws Exception { + testContextManager.beforeTestClass(); + verify(trigger, only()).beforeTestClass(testContext); + } + + @Test + public void prepareTestInstanceAnnotation() throws Exception { + testContextManager.prepareTestInstance(testInstance); + verify(trigger, only()).prepareTestInstance(testContext); + } + + @Test + public void beforeTestMethodAnnotation() throws Exception { + testContextManager.beforeTestMethod(testInstance, testMethod); + verify(trigger, only()).beforeTestMethod(testContext); + } + + @Test + public void beforeTestExecutionAnnotation() throws Exception { + testContextManager.beforeTestExecution(testInstance, testMethod); + verify(trigger, only()).beforeTestExecution(testContext); + } + + @Test + public void afterTestExecutionAnnotation() throws Exception { + testContextManager.afterTestExecution(testInstance, testMethod, null); + verify(trigger, only()).afterTestExecution(testContext); + } + + @Test + public void afterTestMethodAnnotation() throws Exception { + testContextManager.afterTestMethod(testInstance, testMethod, null); + verify(trigger, only()).afterTestMethod(testContext); + } + + @Test + public void afterTestClassAnnotation() throws Exception { + testContextManager.afterTestClass(); + verify(trigger, only()).afterTestClass(testContext); + } +} diff --git a/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerTests.java b/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerTests.java new file mode 100644 index 000000000000..f803dec7c919 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.event; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.context.TestContext; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.only; +import static org.mockito.BDDMockito.verify; + + +/** + * Unit test for {@link EventPublishingTestExecutionListener}. + * + * @author Frank Scheffler + * @since 5.2 + */ +@RunWith(MockitoJUnitRunner.class) +public class EventPublishingTestExecutionListenerTests { + + @Mock(answer=Answers.RETURNS_DEEP_STUBS) + private TestContext testContext; + + @Captor + private ArgumentCaptor testExecutionEvent; + + + private final EventPublishingTestExecutionListener cut = new EventPublishingTestExecutionListener(); + + private void assertEvent(Class eventClass) { + verify(testContext.getApplicationContext(), only()).publishEvent(testExecutionEvent.capture()); + assertThat(testExecutionEvent.getValue(), instanceOf(eventClass)); + assertThat(testExecutionEvent.getValue().getSource(), equalTo(testContext)); + } + + @Test + public void publishBeforeClassTestExecutionEvent() { + cut.beforeTestClass(testContext); + assertEvent(BeforeTestClassEvent.class); + } + + @Test + public void publishPrepareInstanceTestExecutionEvent() { + cut.prepareTestInstance(testContext); + assertEvent(PrepareTestInstanceEvent.class); + } + + @Test + public void publishBeforeMethodTestExecutionEvent() { + cut.beforeTestMethod(testContext); + assertEvent(BeforeTestMethodEvent.class); + } + + @Test + public void publishBeforeExecutionTestExecutionEvent() { + cut.beforeTestExecution(testContext); + assertEvent(BeforeTestExecutionEvent.class); + } + + @Test + public void publishAfterExecutionTestExecutionEvent() { + cut.afterTestExecution(testContext); + assertEvent(AfterTestExecutionEvent.class); + } + + @Test + public void publishAfterMethodTestExecutionEvent() { + cut.afterTestMethod(testContext); + assertEvent(AfterTestMethodEvent.class); + } + + @Test + public void publishAfterClassTestExecutionEvent() { + cut.afterTestClass(testContext); + assertEvent(AfterTestClassEvent.class); + } +}