Category Archives: Spring

mock Spring bean, encapsulate spring bean

How to mock Spring bean (version 2)

twittergoogle_plusrss

Facebooktwittergoogle_plusredditlinkedinmail

EDIT: As of Spring Boot 1.4.0, faking of Spring Beans is supported natively via annotation @MockBean. Read Spring Boot docs for more info.

About a year ago, I wrote a blog post how to mock Spring Bean. Patterns described there were little bit invasive to the production code.  As one of the readers Colin correctly pointed out in comment, there is better alternative to spy/mock Spring bean based on @Profile annotation. This blog post is going to describe this technique. I used this approach with success at work and also in my side projects.

Note that widespread mocking in your application is often considered as design smell.

Introducing production code

First of all we need code under test to demonstrate mocking. We will use these simple classes:

@Repository
public class AddressDao {
	public String readAddress(String userName) {
		return "3 Dark Corner";
	}
}

@Service
public class AddressService {
	private AddressDao addressDao;
	
	@Autowired
	public AddressService(AddressDao addressDao) {
		this.addressDao = addressDao;
	}
	
	public String getAddressForUser(String userName){
		return addressDao.readAddress(userName);
	}
}

@Service
public class UserService {
	private AddressService addressService;

	@Autowired
	public UserService(AddressService addressService) {
		this.addressService = addressService;
	}
	
	public String getUserDetails(String userName){
		String address = addressService.getAddressForUser(userName);
		return String.format("User %s, %s", userName, address);
	}
}

Of course this code doesn’t make much sense, but will be good to demonstrate how to mock Spring bean. AddressDao just returns string and thus simulates read from some data source. It is autowired into AddressService. This bean is autowired into UserService, which is used to construct string with user name and address.

Notice that we are using constructor injection as field injection is considered as bad practice. If you want to enforce constructor injection for your application, Oliver Gierke (Spring ecosystem developer and Spring Data lead) recently created very nice project Ninjector.

Configuration which scans all these beans is pretty standard Spring Boot main class:

@SpringBootApplication
public class SimpleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SimpleApplication.class, args);
    }
}

Mock Spring bean (without AOP)

Let’s test the AddressService class where we mock AddressDao. We can create this mock via Spring’ @Profiles and @Primary annotations this way:

@Profile("AddressService-test")
@Configuration
public class AddressDaoTestConfiguration {
	@Bean
	@Primary
	public AddressDao addressDao() {
		return Mockito.mock(AddressDao.class);
	}
}

This test configuration will be applied only when Spring profile AddressService-test is active. When it’s applied, it registers bean of type AddressDao, which is mock instance created by Mockito. @Primary annotation tells Spring to use this instance instead of real one when somebody autowire AddressDao bean.

Test class is using JUnit framework:

@ActiveProfiles("AddressService-test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SimpleApplication.class)
public class AddressServiceITest {
	@Autowired 
	private AddressService addressService;

	@Autowired
	private AddressDao addressDao;

	@Test
	public void testGetAddressForUser() {
		// GIVEN
		Mockito.when(addressDao.readAddress("john"))
			.thenReturn("5 Bright Corner");

		// WHEN 
		String actualAddress = addressService.getAddressForUser("john");
  
		// THEN   
		Assert.assertEquals("5 Bright Corner", actualAddress);
	}
}

We activate profile AddressService-test to enable AddressDao mocking. Annotation @RunWith is needed for Spring integration tests and @SpringApplicationConfiguration defines which Spring configuration will be used to construct context for testing. Before the test, we autowire instance of AddressService under test and AddressDao mock.

Subsequent testing method should be clear if you are using Mockito. In GIVEN phase, we record desired behavior into mock instance. In WHEN phase, we execute testing code and in THEN phase, we verify if testing code returned value we expect.

Spy on Spring Bean (without AOP)

For spying example, will be spying on AddressService instance:

@Profile("UserService-test")
@Configuration
public class AddressServiceTestConfiguration {
	@Bean
	@Primary
	public AddressService addressServiceSpy(AddressService addressService) {
		return Mockito.spy(addressService);
	}
}

This Spring configuration will be component scanned only if profile UserService-test will be active. It defines primary bean of type AddressService. @Primary tells Spring to use this instance in case two beans of this type are present in Spring context.  During construction of this bean we autowire existing instance of AddressService from Spring context and use Mockito’s spying feature. The bean we are registering is effectively delegating all the calls to original instance, but Mockito spying allows us to verify interactions on spied instance.

We will test behavior of UserService this way:

@ActiveProfiles("UserService-test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SimpleApplication.class)
public class UserServiceITest {
	@Autowired
	private UserService userService;

	@Autowired
	private AddressService addressService;
 
	@Test
	public void testGetUserDetails() {
		// GIVEN - Spring scanned by SimpleApplication class

		// WHEN
		String actualUserDetails = userService.getUserDetails("john");
 
		// THEN
		Assert.assertEquals("User john, 3 Dark Corner", actualUserDetails);
		Mockito.verify(addressService).getAddressForUser("john");
	}
}

For testing we activate UserService-test profile so our spying configuration will be applied. We autowire UserService which is under test and AddressService, which is being spied via Mockito.

We don’t need to prepare any behavior for testing in GIVEN phase. WHEN phase is obviously executing code under test. In THEN phase we verify if testing code returned value we expect and also if addressService call was executed with correct parameter.

Problems with Mockito and Spring AOP

Let say now we want to use Spring AOP module to handle some cross-cutting concerns. For example to log calls on our Spring beans this way:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
    
@Aspect
@Component
@Slf4j
@Profile("aop") //only for example purposes
public class AddressLogger {
   [email protected]("execution(* net.lkrnac.blog.testing.mockbeanv2.beans.*.*(..))")
    public void logAddressCall(JoinPoint jp){
        log.info("Executing method {}", jp.getSignature());
    }
}

This AOP Aspect is applied before call on Spring beans from package net.lkrnac.blog.testing.mockbeanv2. It is using Lombok’s annotation @Slf4j to log signature of called method. Notice that this bean is created only when aop profile is defined. We are using this profile to separate AOP and non-AOP testing examples. In a real application you wouldn’t want to use such profile.

We also need to enable AspectJ for our application, therefore all the following examples will be using this Spring Boot main class:

@SpringBootApplication
@EnableAspectJAutoProxy
public class AopApplication {
    public static void main(String[] args) {
        SpringApplication.run(AopApplication.class, args);
    }
}

 

AOP constructs are enabled by @EnableAspectJAutoProxy.

But such AOP constructs may be problematic if we combine Mockito for mocking with Spring AOP. It is because both use CGLIB to proxy real instances and when Mockito proxy is wrapped into Spring proxy, we can experience type mismatch problems. These can be mitigated by configuring bean’s scope with ScopedProxyMode.TARGET_CLASS, but Mockito verify() calls still fail with NotAMockException. Such problems can be seen if we enable aop profile for UserServiceITest.

Mock Spring bean proxied by Spring AOP

To overcome these problems, we will wrap mock into this Spring bean:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;

import org.mockito.Mockito;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;

import lombok.Getter;
import net.lkrnac.blog.testing.mockbeanv2.beans.AddressDao;

@Primary
@Repository
@Profile("AddressService-aop-mock-test")
public class AddressDaoMock extends AddressDao{
   [email protected]
    private AddressDao mockDelegate = Mockito.mock(AddressDao.class);
    
    public String readAddress(String userName) {
        return mockDelegate.readAddress(userName);
    }
}

@Primary annotation makes sure that this bean will take precedence before real AddressDao bean during injection. To make sure it will be applied only for specific test, we define profile AddressService-aop-mock-test for this bean. It inherits AddressDao class, so that it can act as full replacement of that type.

In order to fake behavior, we define mock instance of type AddressDao, which is exposed via getter defined by Lombok’s @Getter annotation. We also implement readAddress() method which is expected to be called during test. This method just delegates the call to mock instance.

The test where this mock is used can look like this:

@ActiveProfiles({"AddressService-aop-mock-test", "aop"})
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AopApplication.class)
public class AddressServiceAopMockITest {
   [email protected]
    private AddressService addressService; 

   [email protected]
    private AddressDao addressDao;
    
   [email protected]
    public void testGetAddressForUser() {
        // GIVEN
        AddressDaoMock addressDaoMock = (AddressDaoMock) addressDao;
        Mockito.when(addressDaoMock.getMockDelegate().readAddress("john"))
            .thenReturn("5 Bright Corner");
 
        // WHEN 
        String actualAddress = addressService.getAddressForUser("john");
 
        // THEN  
        Assert.assertEquals("5 Bright Corner", actualAddress);
    }
}

In the test we define AddressService-aop-mock-test profile to activate AddressDaoMock and aop profile to activate AddressLogger AOP aspect. For testing, we autowire testing bean addressService and its faked dependency addressDao. As we know, addressDao will be of type AddressDaoMock, because this bean was marked as @Primary. Therefore we can cast it and record behavior into mockDelegate.

When we call testing method, recorded behavior should be used because we expect testing method to use AddressDao dependency.

Spy on Spring bean proxied by Spring AOP

Similar pattern can be used for spying the real implementation. This is how our spy can look like:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;

import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import lombok.Getter;
import net.lkrnac.blog.testing.mockbeanv2.beans.AddressDao;
import net.lkrnac.blog.testing.mockbeanv2.beans.AddressService;

@Primary
@Service
@Profile("UserService-aop-test")
public class AddressServiceSpy extends AddressService{
   [email protected]
    private AddressService spyDelegate;
    
   [email protected]
    public AddressServiceSpy(AddressDao addressDao) {
        super(null);
        spyDelegate = Mockito.spy(new AddressService(addressDao));
    }
    
    public String getAddressForUser(String userName){
        return spyDelegate.getAddressForUser(userName);
    }
}

As we can see this spy is very similar to AddressDaoMock. But in this case real bean is using constructor injection to autowire its dependency. Therefore we’ll need to define non-default constructor and do constructor injection also. But we wouldn’t pass injected dependency into parent constructor.

To enable spying on real object, we construct new instance with all the dependencies, wrap it into Mockito spy instance and store it into spyDelegate property. We expect call of method getAddressForUser() during test, therefore we delegate this call to spyDelegate. This property can be accessed in test via getter defined by Lombok’s @Getter annotation.

Test itself would look like this:

@ActiveProfiles({"UserService-aop-test", "aop"})
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AopApplication.class)
public class UserServiceAopITest {
   [email protected]
    private UserService userService;

   [email protected]
    private AddressService addressService;
    
   [email protected]
    public void testGetUserDetails() {
        // GIVEN
        AddressServiceSpy addressServiceSpy = (AddressServiceSpy) addressService;

        // WHEN
        String actualUserDetails = userService.getUserDetails("john");
  
        // THEN 
        Assert.assertEquals("User john, 3 Dark Corner", actualUserDetails);
        Mockito.verify(addressServiceSpy.getSpyDelegate()).getAddressForUser("john");
    }
}

It is very straight forward. Profile UserService-aop-test ensures that AddressServiceSpy will be scanned. Profile aop ensures same for AddressLogger aspect. When we autowire testing object UserService and its dependency AddressService, we know that we can cast it to AddressServiceSpy and verify the call on its spyDelegate property after calling the testing method.

Fake Spring bean proxied by Spring AOP

It is obvious that delegating calls into Mockito mocks or spies complicates the testing. These patterns are often overkill if we simply need to fake the logic. We can use such fake in that case:

@Primary
@Repository
@Profile("AddressService-aop-fake-test")
public class AddressDaoFake extends AddressDao{
    public String readAddress(String userName) {
        return userName + "'s address";
    }
}

and used it for testing this way:

@ActiveProfiles({"AddressService-aop-fake-test", "aop"})
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AopApplication.class)
public class AddressServiceAopFakeITest {
   [email protected]
    private AddressService addressService; 

   [email protected]
    public void testGetAddressForUser() {
        // GIVEN - Spring context
 
        // WHEN 
        String actualAddress = addressService.getAddressForUser("john");
 
        // THEN  
        Assert.assertEquals("john's address", actualAddress);
    }
}

I don’t think this test needs explanation.

Source code for these examples is hosted on Github.

twittergoogle_plusrss
enterprise spring examples and integration tests

Enterprise Spring examples and integration tests

twittergoogle_plusrss

Facebooktwittergoogle_plusredditlinkedinmail

There was longer gap in my blog, because I was busy writing book Pivotal Certified Spring Enterprise Integration Specialist Exam – A Study Guide. This book is example heavy. Fortunately Apress agreed to open source all these examples. Therefore there is quite extensive collection of Spring examples available in this GitHub repository. Altogether  146 Spring examples with integration tests.

Most of the examples use Spring Boot. But as book is not focused on this modern framework, therefore there are included also plain Spring Framework examples. So is is possible can compare how Spring Boot can simplify Spring developer’s life. Most of the examples are covered with Java and also with XML configuration (where it make sense), therefore it provides also good comparison between these two approaches.

Examples cover main Enterprise Spring features of:

  • Spring Tasks and Scheduling
  • Spring Remoting (RMI, HttpInvoker, Hessian, Burlap)
  • Spring Web Services (SOAP)
  • REST Services with Spring (Spring MVC and JAX-RS)
  • Spring JMS
  • Spring JMS transactions and acknowledge modes
  • Distributed Transactions with Spring
  • Spring Integration
  • Spring Batch

As I am test infected, I wanted to make sure that examples are working. Therefore extensive test suite was created, where each example is backed up by integration test. These tests can be useful as ideas for integration testing of Spring applications.

Few examples are used to highlight error handling features of Spring, therefore there are sometimes errors simulated in example logic. Book would be needed to fully understand intentions of these examples. Some examples cover advanced Spring topics (e.g. Distributed Transactions, Spring Batch Remote Chunking or Spring Batch Remote Partitioning). Examples for these topics are not very common on web, so these simplistic examples can help grasp advanced these Spring features.

Hope somebody will find this battery of examples and tests valuable and possibly give a chance to this book.

twittergoogle_plusrss
mock Spring bean, encapsulate spring bean

How to encapsulate Spring bean

twittergoogle_plusrss

Facebooktwittergoogle_plusredditlinkedinmail

As far as I know Spring Framework doesn’t provide any mechanism to encapsulate Spring beans other than having separate contexts. So when you have public class registered in Spring’s Inversion of Control container, it can be autowired in any Spring bean from same context configuration. This is very powerful but it is also very dangerous. Developers can easily couple beans together. With lack of discipline team can easily shoot themselves in foot. Unfortunately I was working on one monolithic project where team was shooting themselves into foot with submachine gun. Wiring was breaking layering rules often. Nobody could easily follow what is dependent on what. Bean dependency graph was just crazy. This is serious concern in bigger applications.

Luckily there is one simple way how to encapsulate Spring bean. Spring works nicely with default access modifier on class level. So you can create package private bean, which can be used only within current package. Simple and powerful. Let’s take a look at example:

package net.lkrnac.blog.spring.encapsulatebean.service;

import org.springframework.stereotype.Service;

@Service
class AddressService {
	public String getAddress(String userName){
		return "3 Dark Corner";
	}
}

This simple bean is wired into another one within same package:

package net.lkrnac.blog.spring.encapsulatebean.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
	private AddressService addressService;

	@Autowired
	public UserService(AddressService addressService) {
		this.addressService = addressService;
	}
	
	public String getUserDetails(String userName){
		String address = addressService.getAddress(userName);
		return String.format("User: %s, %s", userName, address);
	}
}

Main context just scans both beans:

package net.lkrnac.blog.spring.encapsulatebean;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
}

Here is test to prove it works fine:

package net.lkrnac.blog.spring.encapsulatebean;

import net.lkrnac.blog.spring.encapsulatebean.service.UserService;

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

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTests {
	@Autowired
	private UserService userService;
	
	@Test
	public void isPackagePrivateBeanCalled(){
		//GIVEN - spring context defined by Application class
		
		//WHEN
		String actualUserDetails = userService.getUserDetails("john");
		
		//THEN
		Assert.assertEquals("User: john, 3 Dark Corner", actualUserDetails);
	}
}

I believe everybody should consider using default access modifier for every new bean. Obviously there would need to be some public bean within each package. But at not every bean. Source code is on GitHub.

 

twittergoogle_plusrss

Avoid unwanted component scanning of Spring Configuration

twittergoogle_plusrss

Facebooktwittergoogle_plusredditlinkedinmail

I came through interesting problem on Stack Overflow. Brett Ryan had problem that Spring Security configuration was initialized twice. When I was looking into his code I spot the problem. Let me show show the code.

He has pretty standard Spring application (not using Spring Boot). Uses more modern Java servlet Configuration based on Spring’s AbstractAnnotationConfigDispatcherServletInitializer.

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class AppInitializer extends
		AbstractAnnotationConfigDispatcherServletInitializer {


    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

}

As you can see, there are two configuration classes:

  • SecurityConfig – holds Spring Security configuration
  • WebConfig – main Spring’s IoC container configuration
package net.lkrnac.blog.dontscanconfigurations;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        System.out.println("Spring Security init...");
        auth
                .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }

}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "net.lkrnac.blog.dontscanconfigurations")
public class WebConfig extends WebMvcConfigurerAdapter {

}

Pay attention to the component scanning in WebConfig. It is scanning package where all three classes are located. When you run this on servlet container, text “Spring Security init…” is written to console twice. It mean mean SecurityConfig configuration is loaded twice. It was loaded

  1. During initialization of servlet container in method AppInitializer.getRootConfigClasses()
  2. By component scan in class WebConfig

Why? I found this explanation in Spring’s documentation:

Remember that @Configuration classes are meta-annotated with @Component, so they are candidates for component-scanning!

So this is feature of Spring and therefore we want to avoid component scanning of Spring @Configuration used by Servlet configuration. Brett Ryan independently found this problem and showed his solution in mentioned Stack Overflow question:

@ComponentScan(basePackages = "com.acme.app",
               excludeFilters = {
                   @Filter(type = ASSIGNABLE_TYPE,
                           value = {
                               WebConfig.class,
                               SecurityConfig.class
                           })
               })

I don’t like this solution. Annotation is too verbose for me. Also some developer can create new @Configuration class and forget to include it into this filter. I would rather specify special package that would be excluded from Spring’s component scanning.

I created sample project on Github so that you can play with it.

 

twittergoogle_plusrss

Spring Security Misconfiguration

twittergoogle_plusrss

Facebooktwittergoogle_plusredditlinkedinmail

I recently saw Mike Wienser’s SpringOne2GX talk about Application Security Pitfalls. It is very informative and worth watching if you are using Spring’s stack on servlet container.

It reminded me one serious Spring Security Misconfiguration I was facing once. Going to explain it on Spring’s Guide Project called Securing a Web Application. This project uses Spring Boot, Spring Integration and Spring MVC.

Project uses these views:

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
    
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/home").setViewName("home");
        registry.addViewController("/").setViewName("home");
        registry.addViewController("/hello").setViewName("hello");
        registry.addViewController("/login").setViewName("login");
    }

}

Where “/home”, “/” and “/login” URLs should be publicly accessible and “/hello” should be accessible only to authenticated user. Here is original Spring Security configuration from Guide:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated();
        http
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }
}

Nice and explanatory as all Spring’s Guides are. First “configure” method registers “/” and “home” as public and specifies that everything else should be authenticated. It also registers login URL. Second “configure” method specifies authentication method for role “USER”. Of course you don’t want to use it like this in production :).

Now I am going to slightly amend this code.

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //!!! Don't use this example !!!
        http
            .authorizeRequests()              
                .antMatchers("/hello").hasRole("USER");
        
        //... same as above ...
    }

Everything is public and private endpoints have to be listed. You can see that my amended code have the same behavior as original. In fact it saved one line of code.

But there is serious problem with this. What if my I need to introduce new private endpoint? Let’s say I am not aware of the fact that it needs to be registered in Spring Security configuration. My new endpoint would be public. Such misconfiguration is really hard to catch and can lead to unwanted exposure of URLs.

So conclusion is: Always authenticate all endpoints by default.

twittergoogle_plusrss