How can I inject mocks into spring security classes - java

I am using #PreAuthorize to secure a web request
#PreAuthorize("(#assessmentAuthService.canViewAssessment(#id))")
AssessmentAuthService is created automatically by spring, but I need to inject a mock object into it from my unit test.
private final AssessmentService assessmentService;
#Inject
public AssessmentAuthorizationServiceImpl(AssessmentService assessmentService) {
this.assessmentService = assessmentService;
}
This is because I want assessmentService.getById(assessmentId) to return a mocked object.
I already tried setting it with this but it doesn't work:
ReflectionTestUtils.setField(assessmentAuthorizationService,
"assessmentService", mockAssessmentService);

I was trying to inject a mock into AssessmentAuthorizationService with ReflectionTestUtils.setField but I didn't realize that spring beans are proxies. I had to use this method to unwrap the proxy before I set the field.
class TestUtils {
...
public static Object unwrapService(Object service) throws Exception {
final boolean aopProxy = AopUtils.isAopProxy(service);
final boolean instanceCheck = service instanceof Advised;
if (aopProxy && instanceCheck) {
Object target = ((Advised) service).getTargetSource().getTarget();
return target;
}
return null;
}
}
After I did that it worked. I could set the field to a mock and the define the behavior that I wanted.
ReflectionTestUtils.setField(TestUtil.unwrapService(assessmentAuthorizationService),
"assessmentService", mockAssessmentService);
when(mockAssessmentService.getById(eq(2L))).thenReturn(Optional.of(assessment));

Related

How to spy on injected singleton?

I have a validation method in a model class that gets called from code that I don't have control over. This validation method has parameters that come from dependency injection. One of these parameters is a singleton (#Singleton) class.
#Singleton
public class ObjValidation {
#Inject
public ObjValidation() {
objsCache = new HashSet<>();
}
public boolean exists(String obj) {
return objsCache.contains(obj) || lookupObj(obj);
}
...
}
As you can see this singleton does perform a lookup on a database if the object isn't contained in the cache. While testing this database isn't there and should not be tested. Therefore I'm trying to mock the exists() method to return true without being run.
My first thought was, since this is a singleton, if I would inject the singleton into my test case before running it, I would create the singleton instance therefore could spy on it.
ObjValidation objValidation = spy(app.injector().instanceOf(ObjValidation.class));
doReturn(true).when(objValidation).exists(any());
But yes, spy only returns a copy and therefore doesn't spy on the instantiated singleton. I would need to replace the singleton instance with the spy copy to make it work this way.
How can I do this?
Further explanation of the test case:
In my test (method under test is register()) I bind a scala.html view form to a model class via the build in functionality of the play framework.
public Result register() throws ResultMessageException {
...
Form<Registration> filledRegistrationForm = this.formFactory.form(Registration.class).bindFromRequest();
...
}
The model has a validation method that has parameters that get injected as described in the play documentation: https://www.playframework.com/documentation/2.6.x/JavaForms#Custom-class-level-constraints-with-DI-support
#ValidateWithDI
public class Registration implements ValidatableWithDI<ValidationError> {
#Required
private String obj;
#Override
public ValidationError validate(ObjValidation objValidation) {
if (!objValidation.exists(obj)) {
return new ValidationError("obj");
}
return null;
}
}
This validation method gets called by the framework while binding the form.

Guice FactoryModuleBuilder an instance with constructor parameters

I´m using Guice to initalize a class with some arguments from a config file
#Provides
#Singleton
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
This class is injected in another class which is singleton as well.
class A{
#Inject private RetryServiceCaller retryServiceCaller;
}
But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.
I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.
Something like this
class A{
#Inject private RetryServiceCaller.Factory retryServiceCallerFactory;
}
Then in my RetryServiceCaller implement this
public interface Factory {
#Inject
RetryServiceCaller create();
}
#Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
this.maxRetryAttempts = maxRetryAttempts;
this.upperBoundary = upperBoundary;
this.lowerBoundary = lowerBoundary;
this.multiplicationFactor = multiplicationFactor;
this.timeout = timeout;
this.incrementTimeout = incrementTimeout;
}
But guice throw me errors saying
No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound
Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a #Provides method, or anything else, and Guice will call get or return an internal Provider automatically.
(The returned Provider will also respect scopes, so you'll need to drop your #Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)
This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.
Your finished binding should look like this:
#Provides
/* NOT #Singleton */
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
And in your class:
#Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
this.callerProvider = callerProvider;
}
public void doAction() {
RetryServiceCaller newCaller = callerProvider.get();
// interact with caller
}
Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the #Singleton annotation from the provider method, and a new instance will be created for every injection point.
Assisted inject could work here too, but it's overkill. If you want to go that route:
interface RetryServiceCallerFactory {
RetryServiceCaller create(String configParam1, String configParam2);
}
public class RetryServiceCaller {
#AssistedInject
public RetryServiceCaller(String configParam1, String configParam2) {}
}
then, in your module
install(new FactoryModuleBuilder().build(Factory.class);
and in your injection points
#Inject RetryServiceCallerFactory factory;
RetryServiceCaller create(JsonObject config) {
return factory.create(config.getFirstParam(), config.getSecondParam());
}
You can refer to the documentation for more extensive examples.

What test frameworks to use for mocking a private java class?

I've been working on an application and need to write junit tests for the layer above the Data Access object - I need to mock the data access object and stub values to return for each method. I have tried using mockito but it doesn't seem to work, I think because it has a private constructor.
I have:
Mockito.mock(dataAccessObject.class);
Mockito.when(mockDAO.methodToStub()).thenReturn(returnValue)
but it doesnt return the specified returnValue when called.
This is the dataAccessObject I'm tring to mock:
public class DataAccessBean extends NewDataAccessBean
implements ISQLDataAccessBean {
// Instance of ISQLDataAccessBean
private static ISQLDataAccessBean instance = null;
static ISQLDataAccessBean getInstance() throws TrapDABException {
if (instance == null) {
instance = new DataAccessBean ();
}
return instance;
}
private DataAccessBean () throws DAOException {
super("JNDI_LOOKUP","ALIAS");
}
The Methods I am trying to stub values for are all public but when they are called using the mocked object, they return null..
Does anyone know a better test framework to use for this? I have also looked at powermockito plugin but have not been able to get that working either.

Injecting dependency with Guice in non-constructor method

I'm working on a component that creates HTTP requests dynamically, and I'd like to be able to mock those requests for unit testing.
Currently the implementation looks something like this:
class ModelClass {
public void populate() {
HTTPRequest request = new HTTPRequest();
//configure request...
request.send();
}
}
Is there a way to use Guice to instantiate request so I can replace it with an instance of a mock class for testing? The nearest I can figure out would be to add an injector as instance variable of ModelClass:
class ModelClass {
private final Injector injector;
ModelClass(Injector injector){
this.injector = injector;
}
public void populate() {
HTTPRequest request = injector.getInstance(HTTPRequest.class);
//configure request...
request.send();
}
}
But that's basically like using a factory, which misses the point of Guice entirely.
You can inject a provider which provides 'HTTPRequest' instances in your code.
class ModelClass {
#Inject
Provider<HTTPRequest> httpRequestProvider;
public void populate() {
HTTPRequest request = httpRequestProvider.get();
}
}
Then, in your test code, you can mock the 'httpRequestProvider' to return mock 'HTTPRequest' instances.
Provider<HTTPRequest> mockHttpRequestProvider = mock(Provider.class);
when(mockHttpReqestProvider.get()).thenReturn(yourMockHTTPRequestObject);
// Set this mock provider to the ModelClass instance. (You may have to use reflection)
Info on injecting providers: https://github.com/google/guice/wiki/InjectingProviders

How can I select Spring bean instance at runtime

Based on parameters passed to a method, I need to select from one of many Spring beans that are implementations of the same class, but configured with different parameters.
E.g. if user A invokes the method, I need to call dooFoo() on bean A, but if it's user B then I need to call the very same method, only on bean B.
Is there a 'Springier' way of doing this other than sticking all the beans in a map, and deriving a key from the parameters passed to my method?
We face that issue in our project, and we solve it through a Factory-Like class. The client class -the one that needed the bean at runtime- had an instance of the factory, that was injected through Spring:
#Component
public class ImTheClient{
#Autowired
private ImTheFactory factory;
public void doSomething(
Parameters parameters) throws Exception{
IWantThis theInstance = factory.getInstance(parameters);
}
}
So, the IWantThis instance depends on the runtime value of the parameters parameter. The Factory implementation goes like this:
#Component
public class ImTheFactoryImpl implements
ImTheFactory {
#Autowired
private IWantThisBadly anInstance;
#Autowired
private IAlsoWantThis anotherInstance;
#Override
public IWantThis getInstance(Parameters parameters) {
if (parameters.equals(Parameters.THIS)) {
return anInstance;
}
if (parameters.equals(Parameters.THAT)) {
return anotherInstance;
}
return null;
}
}
So, the factory instance holds reference to both of the posible values of the IWantThis class, being IWantThisBadly and IAlsoWantThis both implementations of IWantThis.
Seems like do you want a ServiceLocator using the application context as registry.
See ServiceLocatorFactoryBean support class for creating ServiceLocators mapping keys to bean names without coupling client code to Spring.
Other option is to use a naming convention or annotation based configuration.
for example, assuming that you annotate Services with #ExampleAnnotation("someId"), you can use something like the following Service Locator to retrieve them.
public class AnnotationServiceLocator implements ServiceLocator {
#Autowired
private ApplicationContext context;
private Map<String, Service> services;
public Service getService(String id) {
checkServices();
return services.get(id);
}
private void checkServices() {
if (services == null) {
services = new HashMap<String, Service>();
Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class);
for (Object bean : beans.values()) {
ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class);
services.put(ann.value(), (Service) bean);
}
}
}
}
Sticking them in a map sounds fine. If it's a Spring-managed map (using util:map, or in Java config), that's better than creating it somewhere else, because then Spring owns all the object references and can manage their lifecycle properly.
If the beans (A, B) you are talking about are SessionScope its no problem at all, they will be selected correctly.
public class BusinessLogic {
private BaseClassOfBeanAandB bean;
public void methodCalledByUserAorB() {
bean.doFoo();
}
}

Categories

Resources