001    // Copyright 2007, 2011 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.ioc.test;
016    
017    import org.easymock.EasyMock;
018    import org.easymock.IMocksControl;
019    
020    /**
021     * Contains core logic used by {@link TestBase}, allowing for mock objects to be used outside of a TestNG-based test
022     * suite. A <em>single</em> standard mock control is used for all mock instances. The control does not care about
023     * execution order, but will balk at any unexpected method invocations. This class is thread safe (it used a thread
024     * local to store the mock control).
025     * <p>
026     * This class was originally in the tapestry-ioc module as was moved to tapestry-test; the package name was not changed
027     * to ensure backwards compatibility.
028     */
029    public final class MockTester
030    {
031        private static class ThreadLocalControl extends ThreadLocal<IMocksControl>
032        {
033            @Override
034            protected IMocksControl initialValue()
035            {
036                return EasyMock.createControl();
037            }
038        }
039    
040        private final ThreadLocalControl localControl = new ThreadLocalControl();
041    
042        /**
043         * Invoked after an individual unit test (i.e., a test method invocation) to discard the mock control.
044         */
045        public synchronized void cleanup()
046        {
047            localControl.remove();
048        }
049    
050        public synchronized IMocksControl getMocksControl()
051        {
052            return localControl.get();
053        }
054    
055        /**
056         * Creates a new mock object of the indicated type. The shared mock control does <strong>not</strong> check order,
057         * but does fail on any unexpected method invocations.
058         * 
059         * @param <T>
060         *            the type of the mock object
061         * @param mockClass
062         *            the class to mock
063         * @return the mock object, ready for training
064         */
065        public <T> T newMock(Class<T> mockClass)
066        {
067            return getMocksControl().createMock(mockClass.getSimpleName(), mockClass);
068        }
069    
070        /**
071         * Switches each mock object created by {@link #newMock(Class)} into replay mode (out of the initial training
072         * mode).
073         */
074        public void replay()
075        {
076            getMocksControl().replay();
077        }
078    
079        /**
080         * Verifies that all trained methods have been invoked on all mock objects (created by {@link #newMock(Class)}, then
081         * switches each mock object back to training mode.
082         */
083        public void verify()
084        {
085            IMocksControl control = getMocksControl();
086    
087            control.verify();
088            control.reset();
089        }
090    }