I need to test some security related classes that depend on Spring Security. This code makes use of SecurityContextHolder.getContext()
which is static. How can I test the calling method without setting up an entire security context?
We are using JUnit 4 with Mockito. Mockito was pretty explicit in it's FAQ that static methods where not supported. Is there an alternative? An answer for the Spring Security case would be nice, but I am looking for a solution to the more general problem.
All you need to do is wrap the static method call inside an instance method and then use dependency injection to inject an instance of the wrapper class to the class under test.
Why static code is difficult to test? Because the logic is assigned to the class definition itself not to instances. Considering the fact that you can't overwrite a static method in Java, you can not overwrite a static behavior in a dummy implementation of the class for your unit tests.
Unit testing can be hard especially when you need to test a method that is static, this tutorial will help you to easily mock static methods. Unit testing helps us to cover different scenarios and it is a way to ensure the applications behave as expected under certain circumstances.
Have a look at PowerMock it will allow you to mock out static method, constructors and do all sorts of other crazy things you wouldn't normally be able to do with java. It integrates with most mocking libraries including mockito (look here http://code.google.com/p/powermock/wiki/MockitoUsage13 for an example).
In general I've found this to be a very useful library to have in your testing toolbox (when coding java). The only caveat is that since this library plays around with your bytecode, if you have other libraries that do bytecode instrumentation/manipulation you can run into trouble, but you won't know until you try.
You can refer to the following issue and inject org.springframework.security.core.context.SecurityContextHolderStrategy
instance which functionality is available since Spring Security 3.0.
You should be able to simply call SecurityContextHolder.setContext()
with a mocked SecurityContext
in your setupt code. SecurityContextHolder
just seems to be a thin wrapper around a ThreadLocal
, so it should work fine.
Maybe refactoring code so it accepts some interface instead of getContext()
? You'll need impl which will delegate all work to context, though.
UPDATE: Code will look like
interface SecurityContext {
void foo();
}
class SpringSecurityContext implements SecurityContext {
public void foo() {
// call spring static method here
}
}
class TestSecurityContext implements SecurityContext {
public void foo() {
// test case logic here
}
}
class SecurityContextClient {
private final SecurityContext context;
public SecurityContextClient(SecurityContext context) {
this.context = context;
}
void useSecurity() {
context.foo();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With