1 package com.atlassian.webdriver.testing.rule;
2
3 import com.atlassian.pageobjects.TestedProduct;
4 import com.google.common.base.Supplier;
5 import org.junit.rules.TestRule;
6
7 import static com.atlassian.pageobjects.TestedProductFactory.fromFactory;
8 import static com.google.common.base.Suppliers.memoize;
9
10 /**
11 * <p/>
12 * Static factory for a set of JUnit4-compatible injection rules.
13 *
14 * <p/>
15 * Similar to {@link TestedProductRule}, but more powerful, this set of rules allows for injection of components
16 * living in the context of a tested product or its associated page binder, into test classes and objects.
17 *
18 * <p/>
19 * The product, or its page binder, MUST implement the {@link com.atlassian.pageobjects.inject.InjectionContext}
20 * interface, otherwise no injection will be performed.
21 *
22 * <p/>
23 * To achieve both static and member injection (which also implies that a single tested product instance will
24 * be associated with test class, rather than each test object), combine {@link org.junit.ClassRule}
25 * and @{@link org.junit.Rule} in the following pattern:
26 *
27 * <pre>
28 * @ClassRule
29 * public static TestRule myProductStaticInjectionRule = InjectionRules.forTestClass(MyProduct.class);
30 *
31 * @Rule
32 * public TestRule myProductMemberInjectionRule = InjectionRules.forTestInContext(this);
33 *
34 *
35 * // (fields that will get injected)
36 * @Inject
37 * private static MyProduct myProduct; // per class
38 *
39 * @Inject
40 * private PageBinder myPageBinder; // per test object instance, but the same binder instance
41 *
42 * // etc...
43 * </pre>
44 *
45 * <p/>
46 * You may also choose to use the class rule only, if all you need is static members injection.
47 *
48 * <p/>
49 * If you prefer having a new tested product created for each test method, use the following factory in conjunction with
50 * {@link org.junit.Rule} annotation:
51 *<pre>
52 * @Rule
53 * public TestRule myProductMemberInjectionRule = TestInjectionRule.forTest(this, MyProduct.class);
54 *
55 * // (fields that will get injected)
56 *
57 * @Inject
58 * private PageBinder myPageBinder; // per test object instance, but the same binder instance
59 *
60 * // etc...
61 * </pre>
62 *
63 * <p/>
64 * An example test class
65 *
66 * <p/>
67 * IMPORTANT: the methods {@link #forTestInContext(Object)} and {@link #forTest(Object, Class)} provide different
68 * implementations of rules, the first of which depends on a class rule created via {@link #forTestClass(Class)}
69 * being present on the test class. Please choose one of the above options for your test (or base test) depending whether
70 * you need just static or just member injection, or both.
71 *
72 * @since 2.1
73 */
74 public final class InjectionRules
75 {
76
77 private InjectionRules()
78 {
79 throw new AssertionError("Don't instantiate me");
80 }
81
82 public static <T extends TestedProduct<?>> InjectingTestRule forTestClass(Class<T> productClass)
83 {
84 return new ClassInjectionRule<T>(memoize(fromFactory(productClass)));
85 }
86
87 public static <T extends TestedProduct<?>> InjectingTestRule forTestClass(Supplier<T> productSupplier)
88 {
89 return new ClassInjectionRule<T>(productSupplier);
90 }
91
92 public static TestRule forTestInContext(Object testInstance)
93 {
94 return new InstanceInjectionRules.InstanceCollaboratingInjectionRule(testInstance);
95 }
96
97 public static <T extends TestedProduct<?>> TestRule forTest(Object testInstance, Class<T> testedProductClass)
98 {
99 return new InstanceInjectionRules.InstanceStandaloneInjectionRule<T>(testInstance, memoize(fromFactory(testedProductClass)));
100 }
101
102 public static <T extends TestedProduct<?>> TestRule forTest(Object testInstance, Supplier<T> productSupplier)
103 {
104 return new InstanceInjectionRules.InstanceStandaloneInjectionRule<T>(testInstance, productSupplier);
105 }
106 }