Coverage Report - com.javaforge.tapestry.testng.TestBase
 
Classes in this File Line Coverage Branch Coverage Complexity
TestBase
96% 
100% 
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  
 }