/** * Copyright 2014 55 Minutes (http://www.55minutes.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fiftyfive.wicket.shiro.test; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadState; import org.junit.After; import org.junit.Before; import org.mockito.Mockito; /** * Enables {@link org.apache.wicket.util.tester.WicketTester WicketTester} to be used with * a Shiro-enabled Wicket application by mocking * the Shiro infrastructure. The code is not Wicket-specific, so you can use this for testing * non-Wicket code as well. Just make this the base class for your JUnit tests. * <b>Requires JUnit 4, Mockito.</b> * <p> * During your tests, mock the authentication state like this: * <pre class="example"> * // Simulate authenticated user * when(this.mockSubject.isAuthenticated()).thenReturn(true); * * // Simulate absence of "admin" role * doThrow(new AuthorizationException()).when(this.mockSubject).checkRole("admin");</pre> * <p> * If you're not using JUnit 4 and Mockito or otherwise can't subclass this class, * you can implement the same technique that this class uses with the testing frameworks of your * choice. This class simply does the following: * <pre class="example"> * // Run before every test so that SecurityUtils.getSubject() returns a mock: * this.mockSubject = Mockito.mock(org.apache.shiro.subject.Subject.class); * this.threadState = new org.apache.shiro.subject.support.SubjectThreadState(this.mockSubject); * this.threadState.bind(); * * // Run after every test to clear the thread local: * this.threadState.clear();</pre> * * @since 3.0 */ public abstract class AbstractShiroJUnit4Tests { private ThreadState threadState; /** * The Mockito mock that will be returned by * {@link org.apache.shiro.SecurityUtils#getSubject() SecurityUtils.getSubject()}. * Use this mock in your tests to mock authentication and authorization prerequisites. */ protected Subject mockSubject; /** * The Mockito mock that will be returned by * {@link Subject#getSession() SecurityUtils.getSubject().getSession()}. */ protected Session mockShiroSession; /** * Install a Mockito mock of {@link Subject} in Shiro's thread local. This causes the mock * to be returned when application code (and fiftyfive-wicket-shiro code) calls * {@link org.apache.shiro.SecurityUtils#getSubject() SecurityUtils.getSubject()}. */ @Before public void attachSubject() { this.mockShiroSession = Mockito.mock(Session.class); this.mockSubject = Mockito.mock(Subject.class); Mockito.when(this.mockSubject.getSession()).thenReturn(this.mockShiroSession); this.threadState = new SubjectThreadState(this.mockSubject); this.threadState.bind(); } /** * Clear Shiro's thread local so that any subject mocking we've done during the test does * not pollute subsequent tests. */ @After public void detachSubject() { this.threadState.clear(); } }