| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| TestBase |
|
| 0.0;0 |
| 1 | // Copyright 2006 Howard M. Lewis Ship |
|
| 2 | // |
|
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 4 | // you may not use this file except in compliance with the License. |
|
| 5 | // You may obtain a copy of the License at |
|
| 6 | // |
|
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
|
| 8 | // |
|
| 9 | // Unless required by applicable law or agreed to in writing, software |
|
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
|
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 12 | // See the License for the specific language governing permissions and |
|
| 13 | // limitations under the License. |
|
| 14 | ||
| 15 | package com.javaforge.tapestry.testng; |
|
| 16 | ||
| 17 | import org.apache.tapestry.IMarkupWriter; |
|
| 18 | import org.apache.tapestry.IRequestCycle; |
|
| 19 | import org.apache.tapestry.test.Creator; |
|
| 20 | import org.easymock.IMocksControl; |
|
| 21 | import org.testng.Assert; |
|
| 22 | import org.testng.annotations.AfterMethod; |
|
| 23 | ||
| 24 | import static org.easymock.EasyMock.createStrictControl; |
|
| 25 | ||
| 26 | /** |
|
| 27 | * A base class for creating TestNG unit tests for Tapestry 4 applications. With slightly more |
|
| 28 | * effort, this may be used as a utility class with other frameworks, such as JUnit. |
|
| 29 | * <p> |
|
| 30 | * A single <em>strict</em> mock control is used for <strong>all</strong> mocks, which means that |
|
| 31 | * order of operations is checked not just for any single mock but across mocks. |
|
| 32 | * <p> |
|
| 33 | * Provides common mock factory and mock trainer methods. |
|
| 34 | * <p> |
|
| 35 | * Provides easy access to instantiated component instances. |
|
| 36 | * <p> |
|
| 37 | * Extends from {@link org.testng.Assert} to bring in all the public static assert methods without |
|
| 38 | * requiring extra imports. |
|
| 39 | * <p> |
|
| 40 | * TestNG supports running tests in parallel, as does this class. The EasyMock control is stored in |
|
| 41 | * a <em>thread local</em>. This is necessary as TestNG instantiates a single instance of the |
|
| 42 | * test case class, and invokes methods on it from multiple threads. |
|
| 43 | * |
|
| 44 | * @author Howard M. Lewis Ship |
|
| 45 | */ |
|
| 46 | 9 | public class TestBase extends Assert |
| 47 | { |
|
| 48 | 99 | private static class ControlSource extends ThreadLocal<IMocksControl> |
| 49 | { |
|
| 50 | /** Creates a strick control for <em>this</em> thread. */ |
|
| 51 | @Override |
|
| 52 | protected IMocksControl initialValue() |
|
| 53 | { |
|
| 54 | 81 | return createStrictControl(); |
| 55 | } |
|
| 56 | } |
|
| 57 | ||
| 58 | 9 | private final ControlSource _source = new ControlSource(); |
| 59 | ||
| 60 | // Access to this is synchronized. |
|
| 61 | ||
| 62 | private Creator _creator; |
|
| 63 | ||
| 64 | /** |
|
| 65 | * Creates a new instance of the provided class using the |
|
| 66 | * {@link org.apache.tapestry.test.Creator} utility. |
|
| 67 | * |
|
| 68 | * @param <T> |
|
| 69 | * the component type |
|
| 70 | * @param componentClass |
|
| 71 | * @param properties |
|
| 72 | * alternating property names and property values to be injected into the instance |
|
| 73 | * @return the instantiated and configured component instance |
|
| 74 | */ |
|
| 75 | public synchronized final <T> T newInstance(Class<T> componentClass, Object... properties) |
|
| 76 | { |
|
| 77 | 6 | if (_creator == null) |
| 78 | 3 | _creator = new Creator(); |
| 79 | ||
| 80 | 6 | Object instance = _creator.newInstance(componentClass, properties); |
| 81 | ||
| 82 | 6 | return componentClass.cast(instance); |
| 83 | } |
|
| 84 | ||
| 85 | /** |
|
| 86 | * Discards any mock objects created during the test. When using TestBase as a utility class, |
|
| 87 | * not a base class, you must be careful to either invoke this method, or discard the TestBase |
|
| 88 | * instance at the end of each test. |
|
| 89 | */ |
|
| 90 | @AfterMethod(alwaysRun = true) |
|
| 91 | public final void cleanupControlSource() |
|
| 92 | { |
|
| 93 | // TestNG reuses the same class instance across all tests within that |
|
| 94 | // class, so if we don't |
|
| 95 | // clear out the mocks, they will tend to accumulate. That can get |
|
| 96 | // expensive, and can |
|
| 97 | // cause unexpected cascade errors when an earlier test fails. |
|
| 98 | ||
| 99 | // After each method runs, we clear this thread's mocks control. |
|
| 100 | 87 | _source.remove(); |
| 101 | 87 | } |
| 102 | ||
| 103 | /** |
|
| 104 | * Creates a new mock object of the indicated type. The created object is retained for the |
|
| 105 | * duration of the test (specifically to support {@link #replay()} and {@link #verify()}). |
|
| 106 | * |
|
| 107 | * @param <T> |
|
| 108 | * the type of the mock object |
|
| 109 | * @param mockClass |
|
| 110 | * the class to mock |
|
| 111 | * @return the mock object, ready for training |
|
| 112 | */ |
|
| 113 | public final <T> T newMock(Class<T> mockClass) |
|
| 114 | { |
|
| 115 | 84 | return getMocksControl().createMock(mockClass); |
| 116 | } |
|
| 117 | ||
| 118 | /** |
|
| 119 | * Replay's the mocks control, preparing all mocks for testing. |
|
| 120 | */ |
|
| 121 | public final void replay() |
|
| 122 | { |
|
| 123 | 81 | getMocksControl().replay(); |
| 124 | 81 | } |
| 125 | ||
| 126 | /** |
|
| 127 | * Verifies the mocks control, ensuring that all mocks completed all trained method invocations, |
|
| 128 | * then resets the control to allow more training of the mocks. |
|
| 129 | */ |
|
| 130 | public final void verify() |
|
| 131 | { |
|
| 132 | 72 | IMocksControl control = getMocksControl(); |
| 133 | ||
| 134 | 72 | control.verify(); |
| 135 | 72 | control.reset(); |
| 136 | 72 | } |
| 137 | ||
| 138 | /** Returns the control object used for all mocks created by this test case. */ |
|
| 139 | public final IMocksControl getMocksControl() |
|
| 140 | { |
|
| 141 | 264 | return _source.get(); |
| 142 | } |
|
| 143 | ||
| 144 | /** |
|
| 145 | * Sets the return value for the most recent method call upon the mock. |
|
| 146 | * |
|
| 147 | * @param returnValue |
|
| 148 | * value to be returned from the method call |
|
| 149 | */ |
|
| 150 | @SuppressWarnings("unchecked") |
|
| 151 | public final <T> void setReturnValue(T returnValue) |
|
| 152 | { |
|
| 153 | 24 | getMocksControl().andReturn(returnValue); |
| 154 | 24 | } |
| 155 | ||
| 156 | /** |
|
| 157 | * Trains a mock object to throw an exception. |
|
| 158 | * |
|
| 159 | * @param throwable |
|
| 160 | * the exception to be thrown by the most recent method call on the mock |
|
| 161 | */ |
|
| 162 | public final void setThrowable(Throwable throwable) |
|
| 163 | { |
|
| 164 | 3 | getMocksControl().andThrow(throwable); |
| 165 | 3 | } |
| 166 | ||
| 167 | /** |
|
| 168 | * Invoked to indicate code should not reach a point. This is typically used after code that |
|
| 169 | * should throw an exception. |
|
| 170 | */ |
|
| 171 | public final void unreachable() |
|
| 172 | { |
|
| 173 | 3 | fail("This code should not be reachable."); |
| 174 | 0 | } |
| 175 | ||
| 176 | /** Mock factory method. */ |
|
| 177 | public final IRequestCycle newRequestCycle() |
|
| 178 | { |
|
| 179 | 3 | return newMock(IRequestCycle.class); |
| 180 | } |
|
| 181 | ||
| 182 | /** Mock factory method. */ |
|
| 183 | public final IMarkupWriter newMarkupWriter() |
|
| 184 | { |
|
| 185 | 60 | return newMock(IMarkupWriter.class); |
| 186 | } |
|
| 187 | } |