Showing posts with label Unit tests. Show all posts
Showing posts with label Unit tests. Show all posts

Wednesday, August 28, 2013

Mockito Instant - my book has finally been published!

I am very pleased to announce that my book about Mockito entitled "Mockito Instant" has finally been published! You can buy it at Packt Publishing online shop.

Wednesday, June 12, 2013

Mockito - Extra Interfaces with annotations and static methods


In the code I have quite recently came across a really bad piece of code that based on class casting in terms of performing some actions on objects. Of course the code needed to be refactored but sometimes you can't do it / or don't want to do it (and it should be understandable) if first you don't have unit tests of that functionality. In the following post I will show how to test such code, how to refactor it and in fact what I think about such code ;)

Tuesday, January 15, 2013

Drools integration with Spring vs manual rules creation



Hi!

 Often in your work you can come across with issues related to business logic. Let us assume that you have dozens of rules (for the time being in our project we have more than 50 and I used to work on a project where we had hundreds of those rules) that you have to implement, divide into some classes, subclasses, abstractions and of course unit test. This can be difficult and timeconsuming to both write and support. There are many ways of dealing with this problem and I will show you one of them - JBoss Drools.

Drools is a library specifically created for such purposes like implementing rules. As presented in Wikipedia:
"Drools is a rule engine implementaion based on Charles Forgy's Rete Algorithm tailored for the Java language." 
It contains a rule engine that can process rules wirtten using the Drools language (you can also provide rules in Excel spreadsheets! - perfect for Business side to support and maintain).

In the following example we will take a look at the way one can integrate JBoss Drools with Spring and an example of solving a similar problem without Drools.


Saturday, October 27, 2012

Spring AOP in security - controlling creation of UI components via aspects



The following post will show how in one of the projects that I took part in we used Spring's AOP to introduce some security related functionalities. The concept was such that in order for the user to see some UI components he needed to have a certain level of security privillages. If that requirement was not met then the UIComponent was not presented. Let's take a look at the project structure:


Then there were also the aopApplicationContext.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

 <aop:aspectj-autoproxy />
 <context:annotation-config />
 <context:component-scan base-package="pl.grzejszczak.marcin.aop">
  <context:exclude-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
 </context:component-scan>
 <bean class="pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor" factory-method="aspectOf"/> 

</beans>

Now let's take a look at the most interesting lines of the Spring's application context.

First we have all the required schemas - I don't think that this needs to be explained in more depth.
Then we have:
<aop:aspectj-autoproxy/>


which enables the @AspectJ support.

Next there is the

<context:annotation-config />
<context:component-scan base-package="pl.grzejszczak.marcin.aop">
    <context:exclude-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>

first we are turning on Spring configuration via annotations. Then deliberatly we exclude aspects from being initialized as beans by Spring itself. Why? Because...

<bean class="pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor" factory-method="aspectOf"/>

we want to create the aspect by ourselves and provide the factory-method="aspectOf" . By doing so our aspect will be included in the autowiring process of our beans - thus all the fields annotated with the @Autowired annotation will get the beans injected.

Now let's move on to the code:

UserServiceImpl.java

package pl.grzejszczak.marcin.aop.service;

import org.springframework.stereotype.Service;

import pl.grzejszczak.marcin.aop.type.Role;
import pl.grzejszczak.marcin.aop.user.UserHolder;

@Service
public class UserServiceImpl implements UserService {
 private UserHolder userHolder;

 @Override
 public UserHolder getCurrentUser() {
  return userHolder;
 }

 @Override
 public void setCurrentUser(UserHolder userHolder) {
  this.userHolder = userHolder;
 }

 @Override
 public Role getUserRole() {
  if (userHolder == null) {
   return null;
  }
  return userHolder.getUserRole();
 }
}

The class UserServiceImpl is immitating a service that would get the current user information from the db or from the current application context.

UserHolder.java

package pl.grzejszczak.marcin.aop.user;

import pl.grzejszczak.marcin.aop.type.Role;

public class UserHolder {
 private Role userRole;

 public UserHolder(Role userRole) {
  this.userRole = userRole;
 }

 public Role getUserRole() {
  return userRole;
 }

 public void setUserRole(Role userRole) {
  this.userRole = userRole;
 }
}


This is a simple holder class that holds information about current user Role.

Role.java

package pl.grzejszczak.marcin.aop.type;


public enum Role {
 ADMIN("ADM"), WRITER("WRT"), GUEST("GST");

 private String name;

 private Role(String name) {
  this.name = name;
 }

 public static Role getRoleByName(String name) {

  for (Role role : Role.values()) {

   if (role.name.equals(name)) {
    return role;
   }
  }

  throw new IllegalArgumentException("No such role exists [" + name + "]");
 }

 public String getName() {
  return this.name;
 }

 @Override
 public String toString() {
  return name;
 }
}

Role is an enum that defines a role for a person being an Admin, Writer or a Guest.

UIComponent.java

package pl.grzejszczak.marcin.aop.ui;

public abstract class UIComponent {
 protected String componentName;

 protected String getComponentName() {
  return componentName;
 }

}

An abstraction over concrete implementations of some UI components.

SomeComponentForAdminAndGuest.java

package pl.grzejszczak.marcin.aop.ui;

import pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation;
import pl.grzejszczak.marcin.aop.type.Role;

@SecurityAnnotation(allowedRole = { Role.ADMIN, Role.GUEST })
public class SomeComponentForAdminAndGuest extends UIComponent {

 public SomeComponentForAdminAndGuest() {
  this.componentName = "SomeComponentForAdmin";
 }

 public static UIComponent getComponent() {
  return new SomeComponentForAdminAndGuest();
 }
}

This component is an example of a UI component extention that can be seen only by users who have roles of Admin or Guest.

SecurityAnnotation.java

package pl.grzejszczak.marcin.aop.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import pl.grzejszczak.marcin.aop.type.Role;

@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityAnnotation {
 Role[] allowedRole();
}


Annotation that defines a roles that can have this component created.

UIFactoryImpl.java

package pl.grzejszczak.marcin.aop.ui;

import org.apache.commons.lang.NullArgumentException;
import org.springframework.stereotype.Component;

@Component
public class UIFactoryImpl implements UIFactory {

 @Override
 public UIComponent createComponent(Class<? extends UIComponent> componentClass) throws Exception {
  if (componentClass == null) {
   throw new NullArgumentException("Provide class for the component");
  }
  return (UIComponent) Class.forName(componentClass.getName()).newInstance();
 }
}


A factory class that given the class of an object that extends UIComponent returns a new instance of the given UIComponent.

SecurityInterceptor.java


package pl.grzejszczak.marcin.aop.interceptor;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation;
import pl.grzejszczak.marcin.aop.service.UserService;
import pl.grzejszczak.marcin.aop.type.Role;
import pl.grzejszczak.marcin.aop.ui.UIComponent;

@Aspect
public class SecurityInterceptor {
 private static final Logger LOGGER = LoggerFactory.getLogger(SecurityInterceptor.class);

 public SecurityInterceptor() {
  LOGGER.debug("Security Interceptor created");
 }

 @Autowired
 private UserService userService;

 @Pointcut("execution(pl.grzejszczak.marcin.aop.ui.UIComponent pl.grzejszczak.marcin.aop.ui.UIFactory.createComponent(..))")
 private void getComponent(ProceedingJoinPoint thisJoinPoint) {
 }

 @Around("getComponent(thisJoinPoint)")
 public UIComponent checkSecurity(ProceedingJoinPoint thisJoinPoint) throws Throwable {
  LOGGER.info("Intercepting creation of a component");

  Object[] arguments = thisJoinPoint.getArgs();
  if (arguments.length == 0) {
   return null;
  }

  Annotation annotation = checkTheAnnotation(arguments);
  boolean securityAnnotationPresent = (annotation != null);

  if (securityAnnotationPresent) {
   boolean userHasRole = verifyRole(annotation);
   if (!userHasRole) {
    LOGGER.info("Current user doesn't have permission to have this component created");
    return null;
   }
  }
  LOGGER.info("Current user has required permissions for creating a component");
  return (UIComponent) thisJoinPoint.proceed();
 }

 /**
  * Basing on the method's argument check if the class is annotataed with
  * {@link SecurityAnnotation}
  * 
  * @param arguments
  * @return
  */
 private Annotation checkTheAnnotation(Object[] arguments) {
  Object concreteClass = arguments[0];
  LOGGER.info("Argument's class - [{}]", new Object[] { arguments });
  AnnotatedElement annotatedElement = (AnnotatedElement) concreteClass;
  Annotation annotation = annotatedElement.getAnnotation(SecurityAnnotation.class);
  LOGGER.info("Annotation present - [{}]", new Object[] { annotation });
  return annotation;
 }

 /**
  * The function verifies if the current user has sufficient privilages to
  * have the component built
  * 
  * @param annotation
  * @return
  */
 private boolean verifyRole(Annotation annotation) {
  LOGGER.info("Security annotation is present so checking if the user can use it");
  SecurityAnnotation annotationRule = (SecurityAnnotation) annotation;
  List<Role> requiredRolesList = Arrays.asList(annotationRule.allowedRole());
  Role userRole = userService.getUserRole();
  return requiredRolesList.contains(userRole);
 }
}


This is the aspect defined at the pointcut of executing a function createComponent of the UIFactory interface. Inside the Around advice there is the logic that first checks what kind of an argument has been passed to the method createComponent (for example SomeComponentForAdminAndGuest.class). Next it is checking if this class is annotated with SecurityAnnotation and if that is the case it checks what kind of Roles are required to have the component created. Afterwards it checks if the current user (from UserService to UserHolder's Roles) has the required role to present the component. If that is the case thisJoinPoint.proceed() is called which in effect returns the object of the class that extends UIComponent.

Now let's test it - here comes the SpringJUnit4ClassRunner

AopTest.java

package pl.grzejszczak.marcin.aop;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import pl.grzejszczak.marcin.aop.service.UserService;
import pl.grzejszczak.marcin.aop.type.Role;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForAdmin;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForAdminAndGuest;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForGuest;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForWriter;
import pl.grzejszczak.marcin.aop.ui.UIFactory;
import pl.grzejszczak.marcin.aop.user.UserHolder;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:aopApplicationContext.xml" })
public class AopTest {

 @Autowired
 private UIFactory uiFactory;

 @Autowired
 private UserService userService;

 @Test
 public void adminTest() throws Exception {
  userService.setCurrentUser(new UserHolder(Role.ADMIN));
  Assert.assertNotNull(uiFactory.createComponent(SomeComponentForAdmin.class));
  Assert.assertNotNull(uiFactory.createComponent(SomeComponentForAdminAndGuest.class));
  Assert.assertNull(uiFactory.createComponent(SomeComponentForGuest.class));
  Assert.assertNull(uiFactory.createComponent(SomeComponentForWriter.class));
 }
}


And the logs:

pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:26 Security Interceptor created
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForAdmin]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[ADM])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:70 Current user has required permissions for creating a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForAdminAndGuest]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[ADM, GST])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:70 Current user has required permissions for creating a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForGuest]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[GST])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:66 Current user doesn't have permission to have this component created
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForWriter]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[WRT])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:66 Current user doesn't have permission to have this component created

The unit test shows that for given Admin role only first two components get created whereas for the two others nulls are returned (due to the fact that user doesn't have proper rights).

That is how in our project we used Spring's AOP to create a simple framework that would check if the user can have the given component created or not. Thanks to this after having programmed the aspects one doesn't have to remember about writing any security related code since it will be done for him.

If you have any suggestions related to this post please feel free to comment it :)

Wednesday, October 24, 2012

Mockito InvocationOnMock - checking an argument



Hi!

In one of my projects we had a very interesting situation in terms of testing. We couldn't mock an invocation of a static method due to the fact that PowerMock was not allowed to be used so there were plenty of objects and dependencies being initialized. What is more we were using a custom made dependency injection system that had a possibility of injecting a mock.

The problem was such that during a test we wanted to assert whether one of the objects was in a very precise state. This object was created using the new operator so we couldn't mock it (again no PowerMock allowed). Fortunately this object got passed to a method of an object that we could mock...

As presented below timeConsumingExternalService is an object that we could mock via the custom dependency injection system whereas the SomePojo class is an object whose state we would like to verify.

timeConsumingExternalService.processSomeObject(new SomePojo("name", "surname", 1, 1.0));

So what we did was that in our mock to which the object got passed we created a new Answer (the same Answer that I spoke of here). Due to which we could access the InvocationOnMock and the arguments passed to the method as such.

Mockito.doAnswer(new Answer<Object>() {
   public Object answer(InvocationOnMock invocation) throws Throwable {
    Object[] object = invocation.getArguments();

      if (object.length > 0) {
          SomePojo somePojo = (SomePojo) object[0];

          Assert.assertEquals("name", somePojo.getName());
          LOGGER.debug("Names are equal");
          Assert.assertEquals("surname", somePojo.getSurname());
          LOGGER.debug("Surnames are equal");
          Assert.assertTrue(1 == somePojo.getIntValue());
          LOGGER.debug("Ints are equal");
          Assert.assertTrue(1.0 == somePojo.getDoubleValue());
          LOGGER.debug("Doubles are equal");

          LOGGER.debug("Object being an argument of the function [" + String.valueOf(somePojo) + "]");
  }
    return null;
   }
  }).when(timeConsumingExternalServiceMock).processSomeObject(Mockito.any(SomePojo.class));

Of course the logs regarding the equalities are unnecessary since if they wouldn't be equal we would have an assertion exception - I left them for the purpose of this post.

And in the logs we can find:

pl.grzejszczak.marcin.ServiceIntegrationTest:48 Names are equal
pl.grzejszczak.marcin.ServiceIntegrationTest:50 Surnames are equal
pl.grzejszczak.marcin.ServiceIntegrationTest:52 Ints are equal
pl.grzejszczak.marcin.ServiceIntegrationTest:54 Doubles are equal
pl.grzejszczak.marcin.ServiceIntegrationTest:56 Object being an argument of the function [SomePojo [name=name, surname=surname, intValue=1, doubleValue=1.0]]

So in this way something that seems impossible to be verified can get verified :)

Update!

Thanks to Holger's suggestion I took a look at the ArgumentCaptor object and that is true that it is an elegant solution to retrieve information about the arguments executed on a method. Where InvocationOnMock can give you much more information and possibilities (for instance regarding the method being executed or just execute the real method) for this particular case a much more elegant, easier and faster way of dealing with the issue would be:


  //service that executes the external service
  executorService.execute(someTask);

  final ArgumentCaptor<SomePojo> argumentCaptor = ArgumentCaptor.forClass(SomePojo.class);
  Mockito.verify(timeConsumingExternalServiceMock).processSomeObject(argumentCaptor.capture());
  SomePojo somePojo = argumentCaptor.getValue();
  Assert.assertEquals("name", somePojo.getName());
  LOGGER.debug("Names are equal");
  Assert.assertEquals("surname", somePojo.getSurname());
  LOGGER.debug("Surnames are equal");
  Assert.assertTrue(1 == somePojo.getIntValue());
  LOGGER.debug("Ints are equal");
  Assert.assertTrue(1.0 == somePojo.getDoubleValue());
  LOGGER.debug("Doubles are equal");

The logs:
pl.grzejszczak.marcin.junit.SomeTask:26 Before processing an object
pl.grzejszczak.marcin.junit.SomeTask:28 After processing an object
pl.grzejszczak.marcin.ServiceIntegrationTest:75 Names are equal
pl.grzejszczak.marcin.ServiceIntegrationTest:77 Surnames are equal
pl.grzejszczak.marcin.ServiceIntegrationTest:79 Ints are equal
pl.grzejszczak.marcin.ServiceIntegrationTest:81 Doubles are equal

Thanks again Holger!