001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.bct.junit;
018
019import static java.lang.annotation.ElementType.*;
020import static java.lang.annotation.RetentionPolicy.*;
021
022import java.lang.annotation.*;
023
024/**
025 * Marks a field or method on a JUnit 5 test class as a test-time bean override.
026 *
027 * <p>
028 * {@code @TestBean} is the Juneau analog of Spring's {@code @MockBean} / {@code @TestConfiguration}, scoped to a
029 * {@code BeanStore} overlay rather than a Spring application context.  The {@link JuneauBeanStoreExtension} discovers
030 * {@code @TestBean}-annotated members on the test class, builds a {@link TestBeanStore} overlay containing the
031 * declared overrides, and exposes it via {@link JuneauBeanStoreExtension#getStore()} so the test author can wire
032 * it into the SUT explicitly (typically via a builder hook such as
033 * {@code MockRestClient.Builder.overridingBeanStore(...)}).
034 *
035 * <p>
036 * The wiring is intentionally <i>explicit</i>: the extension does not auto-discover {@code RestContext} /
037 * {@code Microservice} fields on the test class.  Test authors write one line of plumbing
038 * ({@code .overridingBeanStore(ext.getStore())}) and get full control.
039 *
040 * <p>
041 * The annotation supports two wiring modes via {@link #mode()}: <b>Mode INJECT</b> (default, fresh-instance with
042 * overrides via the SUT's builder) and <b>Mode OVERLAY</b> (existing-instance push/pop against a long-lived
043 * SUT's bean store).  See {@link JuneauBeanStoreExtension} for the full Mode INJECT / Mode OVERLAY contracts.
044 *
045 * <h5 class='section'>Applies to:</h5>
046 * <ul>
047 *    <li><b>Fields</b> &mdash; the field's current value (read via reflection) is registered as the override.
048 *    <li><b>Methods</b> &mdash; a parameterless factory method whose return type is type-compatible with the
049 *       override target.  Invoked once per scope (per-method for {@link Scope#METHOD}, per-class for
050 *       {@link Scope#CLASS}).
051 * </ul>
052 *
053 * <h5 class='section'>Example:</h5>
054 * <p class='bjava'>
055 *    <ja>@ExtendWith</ja>(JuneauBeanStoreExtension.<jk>class</jk>)
056 *    <jk>class</jk> MyResourceTest {
057 *
058 *       <ja>@TestBean</ja>
059 *       MyExternalApi <jv>mockApi</jv> = Mockito.<jsm>mock</jsm>(MyExternalApi.<jk>class</jk>);
060 *
061 *       <ja>@TestBean</ja>(name=<js>"primary"</js>)
062 *       <jk>static</jk> MyService primaryService() { <jk>return new</jk> InMemoryMyService(<js>"p"</js>); }
063 *
064 *       <ja>@Test</ja>
065 *       <jk>void</jk> aTest(TestBeanStore <jv>store</jv>) {
066 *          <jk>var</jk> <jv>client</jv> = MockRestClient.<jsm>create</jsm>(MyResource.<jk>class</jk>)
067 *             .overridingBeanStore(<jv>store</jv>)
068 *             .build();
069 *          <jv>client</jv>.get(<js>"/widgets/1"</js>).run().assertStatus().is(200);
070 *       }
071 *    }
072 * </p>
073 *
074 * <h5 class='section'>See Also:</h5><ul>
075 *    <li class='jc'>{@link JuneauBeanStoreExtension} - The JUnit 5 extension that discovers and applies these annotations.
076 *    <li class='jc'>{@link TestBeanStore} - The overlay builder the extension populates.
077 *    <li class='je'>{@link Scope} - Per-method vs per-class lifecycle selector.
078 * </ul>
079 *
080 * @since 10.0.0
081 */
082@Documented
083@Retention(RUNTIME)
084@Target({ FIELD, METHOD })
085public @interface TestBean {
086
087   /**
088    * Qualifier name for the override.
089    *
090    * <p>
091    * Empty string (the default) means the override is registered as the <i>unnamed</i> bean of its type, matching
092    * the behavior of {@link TestBeanStore#override(Class, Object)} without a name argument.
093    *
094    * <p>
095    * When non-empty, the override is registered under this qualifier so the framework's
096    * {@code @Bean(name = "...")} parameter resolution can find it.  Two {@code @TestBean}-declared overrides of
097    * the same type but different names are both picked up &mdash; the qualifier is the disambiguator.
098    *
099    * @return The qualifier name.  Empty string means "unnamed".
100    * @since 10.0.0
101    */
102   String name() default "";
103
104   /**
105    * Explicit override target type.
106    *
107    * <p>
108    * {@code Object.class} (the default) is a sentinel meaning <i>"use the annotated member's declared type"</i>
109    * &mdash; the field's declared type for field overrides, the method's return type for method overrides.  This
110    * is the common case.
111    *
112    * <p>
113    * Set this explicitly when the member's declared type is a supertype of the intended registration type, for
114    * example an {@code Object} field carrying a {@code MyService} value, or a {@code @TestBean Supplier<MyService>}
115    * factory method whose semantic type is {@code MyService}.
116    *
117    * @return The override target type.  {@code Object.class} means "use the member's declared type".
118    * @since 10.0.0
119    */
120   Class<?> type() default Object.class;
121
122   /**
123    * Lifecycle scope of the override.
124    *
125    * <p>
126    * Defaults to {@link Scope#METHOD} &mdash; the override is rebuilt for every test method.  Use
127    * {@link Scope#CLASS} to share the override across all test methods in the class.
128    *
129    * <p>
130    * {@code CLASS}-scope overrides may only be declared on {@code static} fields and {@code static} methods.
131    * Instance members are not visible at {@code beforeAll} time and will be rejected with an error.
132    *
133    * @return The lifecycle scope.
134    * @since 10.0.0
135    */
136   Scope scope() default Scope.METHOD;
137
138   /**
139    * Wiring mode for the override.
140    *
141    * <p>
142    * Defaults to {@link Mode#INJECT} &mdash; the override is installed at SUT construction time via the SUT's
143    * {@code overridingBeanStore(...)} builder hook.  Use {@link Mode#OVERLAY} for push/pop overlays against a
144    * long-lived SUT that the test has
145    * {@linkplain JuneauBeanStoreExtension#attach(org.apache.juneau.commons.inject.WritableBeanStore) attach}-ed
146    * to the extension.
147    *
148    * <p>
149    * Mixing {@code Mode.INJECT} and {@code Mode.OVERLAY} annotations on the same scope is rejected at scope-build
150    * time with a clear {@link IllegalStateException}.
151    *
152    * @return The wiring mode.
153    * @since 10.0.0
154    */
155   Mode mode() default Mode.INJECT;
156}