When to Use Design Patterns

Lately I've been doing a refresher course on design patterns. I've been wondering if it's worth memorizing them. It seems that once I read about a pattern, I'll want to apply it in a lot of situations while programming. Sometimes I'll work my way into an overly complex solution that has to be simplified later.

I think maybe the best way to approach design patterns is to use the quickest approach to get things working - without applying any patterns. Then, only after things are working, take a break from the code for a few days and sparingly refactor with design patterns if any make themselves apparent.

Of course, there are exceptions to this rule. Patterns like the inversion of control, abstract factory and data access object seem almost too intuitive not to use when initially designing a system.

Java Unit Testing: Mock A Spring Bean Using a Test Spring Context

Spring has a lot of ways to mock beans for testing. Here we'll be setting up a Spring context just for testing, which will have a mock bean.

First, make a new Maven project called 'mock':


mvn archetype:generate -DgroupId=org.vpxd.example -DartifactId=mock -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false


Add Spring to your project:

/pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.vpxd.example</groupId>
  <artifactId>mock</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>mock</name>
  <url>http://maven.apache.org</url>
  <properties>
     <maven.compiler.source>1.7</maven.compiler.source>
     <maven.compiler.target>1.7</maven.compiler.target>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.3.RELEASE</version>
      <scope>test</scope>
  </dependency>
  </dependencies>
</project>


Create a main method that loads up the Spring context:

/src/main/java/org/vpxd/example/App.java


package org.vpxd.example;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
  public static void main(String... args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

    Example example = context.getBean(Example.class);

    System.out.println(example.run());
  }
}


Create a simple Spring context configuration:

/src/main/java/org/vpxd/example/Config.java


package org.vpxd.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages="org.vpxd")
public class Config {

}


Create a Spring bean:

/src/main/java/org/vpxd/example/Example.java


package org.vpxd.example;

public interface Example {
  String run();
}


/src/main/java/org/vpxd/example/ExampleImpl.java


package org.vpxd.example;

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

@Service
public class ExampleImpl implements Example {

  private MockMe mockMe;

  @Autowired
  public ExampleImpl(MockMe mockMe) {
    this.mockMe = mockMe;
  }

  @Override
  public String run() {
    return mockMe.run();
  }
}


Create a Spring bean that will be mocked during testing

/src/main/java/org/vpxd/example/MockMe.java


package org.vpxd.example;

public interface MockMe {
  String run();
}


/src/main/java/org/vpxd/example/MockMeImpl.java


package org.vpxd.example;

import org.springframework.stereotype.Service;

@Service
public class MockMeImpl implements MockMe {

  @Override
  public String run() {
    return "real impl";
  }

}


Create a jar and then run the project, "real impl" should be output:


mvn assembly:assembly -DdescriptorId=jar-with-dependencies
java -cp target/mock-1.0-SNAPSHOT-jar-with-dependencies.jar org.vpxd.example.App


Now we're ready to add the unit test with a testing context configuration. It tests that "test impl" is returned:

/src/test/java/org/vpxd/example/ExampleTest.java


package org.vpxd.example;

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

@RunWith(SpringRunner.class)
@ContextConfiguration(classes=ConfigWithMock.class)
public class ExampleTest {

  @Autowired
  private Example example;

  @Test
  public void testRun() {
    assertEquals("test impl", example.run());
  }
}


Now the test context configuration we used in the unit test above. Instead of component scanning everything, a filter is set up to exclude the actual implementation of the MockMe interface and the actual Config class. A mock implementation is manually defined.

/src/test/java/org/vpxd/example/ConfigWithMock.java


package org.vpxd.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(basePackages="org.vpxd", 
  excludeFilters = {@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=MockMe.class),
  @ComponentScan.Filter(Configuration.class)})
public class ConfigWithMock {

  @Bean
  public MockMe getMockMe() {
    return new MockMeMockImpl();
  }
}


Finally we add the mocked implementation of the MockMe interface:

/src/test/java/org/vpxd/example/MockMeMockImpl.java


package org.vpxd.example;

import org.springframework.stereotype.Service;

@Service
public class MockMeMockImpl implements MockMe {

  @Override
  public String run() {
    return "test impl";
  }

}


Now just run the test:


mvn test