Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are ways to test methods that depend on static methods?

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.

like image 788
Andrew White Avatar asked Apr 18 '11 12:04

Andrew White


People also ask

How do you test the static method?

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.

What makes static methods difficult to 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.

Can we write unit test for static methods?

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.


4 Answers

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.

like image 197
skorks Avatar answered Oct 01 '22 19:10

skorks


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.

like image 21
Constantiner Avatar answered Oct 01 '22 20:10

Constantiner


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.

like image 29
Michael Borgwardt Avatar answered Oct 01 '22 18:10

Michael Borgwardt


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();
    }
}
like image 33
Victor Sorokin Avatar answered Oct 01 '22 18:10

Victor Sorokin