I updated the testing documentation to reflect this: https://cwiki.apache.org/confluence/display/SHIRO/Testing
It should be reflected on http://shiro.apache.org/testing.html within an hour or so. Cheers, Les On Tue, Dec 7, 2010 at 10:00 AM, Les Hazlewood <[email protected]> wrote: > Hi Tauren, > > Matt Brictson recently posted an even better way using mock objects. > You can create a mock Subject instance (since Subject is an interface, > this works great with frameworks like Easymock and Mockito) and mock > what would happen during a security check. Then you bind and unbind > your mock to the thread as necessary. > > If you're using the AbstractShiroTest base class as shown in the > testing.html documentation page, this is all you would have to do (for > example, using JUnit 4 annotations and Easymock): > > import static org.easymock.EasyMock.*; > > public class MyTest extends AbstractShiroTest { > > �...@test > public void testSomething() { > Subject subjectUnderTest = createNiceMock(Subject.class); > expect(subjectUnderTest.isAuthenticated()).andReturn(true); > > //bind the Subject to the thread so SecurityUtils and > //other framework code will work: > setSubject(subjectUnderTest); > > //execute your test logic > } > > } > > Note that your mock subject will remain bound to the thread for all > tests in a class unless you call the clearSubject() method after each > test. > > This can be done in a JUnit @After method for example: > > @After > public void tearDownSubject() { > clearSubject(); > } > > Or, some people may want that to be the case for all tests. You can > mix and match this setup/teardown logic in each method manually or use > the @Before and @After annotations as you see fit. The > AbstractShiroTest class will however unbind the Subject from the > thread at the end of the test class execution because of the > @AfterClass annotation in its tearDownShiro() method. > > The reason this is probably a better approach for most tests is that > most people don't really care about testing the Shiro SecurityManager > and Subject implementations - they typically want to test their own > code that relies on SecurityUtils.getSubject() and the Subject API. > Creating and using the actual SecurityManager and Subject > implementation instances (as is shown in the current testing.html > documentation) is probably better suited for integration tests. > > I'll update the documentation to reflect this approach. > > HTH! > > Best, > > Les > > On Tue, Dec 7, 2010 at 7:45 AM, Tauren Mills <[email protected]> wrote: >> I'm following the instructions on how to do unit testing with Shiro: >> http://shiro.apache.org/testing.html >> I've got everything compiling and running. However, I'm unclear on how to >> actually specify the subject I want to use. The following creates a >> DelegatingSubject, but it appears to be unauthenticated with no principles >> or anything. I know I haven't properly set them, but I'm unsure the right >> way to do it. >> Subject subjectUnderTest = new >> Subject.Builder(getSecurityManager()).buildSubject(); >> My application uses Spring to configure Shiro and it has a custom realm that >> creates permissions. Do I need to create another realm to use only during >> testing? Or can I use my curent realm and force a specific user >> authentication? For instance, I'd like to run my tests assuming that the >> user with an ID of 1 has authenticated. >> Following the testing instructions, I've set up an INI file that gets >> loaded, even though with my normal application, I use Spring to configure >> Shiro. It seems like going with an INI for testing might be simpler. Should >> I be using Spring to configure Shiro for unit testing, or is using INI just >> fine? >> [main] >> sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher >> rememberMeManager = com.company.security.MyRememberMeManager >> rememberMeManager.cipherKey = xymVvsqSTov2/tcoHnax0B== >> myRealm = com.company.security.MyRealm >> myRealm.credentialsMatcher = $sha256Matcher >> securityManager.sessionManager.globalSessionTimeout = 1800000 >> securityManager.rememberMeManager = $rememberMeManager >> [users] >> [roles] >> So what is the simplest way to make user ID 1 authenticated? Should I create >> a custom Realm for testing that has the user hard coded into >> doGetAuthenticationInfo? Or should I be specify the user in the [users] >> section and somehow use it? Or can I pass a custom AuthenticationToken with >> the proper details to my current Realm implementation? How would I do that? >> protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken >> authcToken) throws AuthenticationException { >> UsernamePasswordToken token = (UsernamePasswordToken) authcToken; >> Member member = memberService.findMember(token.getUsername()); >> if (member != null && member.isValidated()) { >> return new SimpleAuthenticationInfo(member.getId(), >> member.getPassword(), getName()); >> } else { >> return null; >> } >> } >> Ideally, I'd just build an AuthenticationToken and somehow pass it to the >> realm.doGetAuthInfo() method. But I'm unclear how that would be >> accomplished. >> Thanks! >> Tauren
