springmock
Introduction
Alternative spring mocking infrastructure. With pluggable mocking library support. The purpose is to allow you to easily inject mocks created by any mocking library into your spring tests. Currently, mockito and spock mocks are supported.
Why? Spring boot supports only mockito as mocks provider which is great if you write tests in java. When using spock you might want to use mocks created by spock because of syntactic sugar they offer. It is similar to @MockBean any @SpyBean from spring-boot-test, but allows you to use mocks created by a library of your choice.
Contents
Features
- inject mocks created by spock/mockito into test case (spock samples, mockito samples)
- extended mocks and spies configuration (spock configuration options, mockito configuration options)
- registration of mocks declared on configuration/test class in spring context (just place @AutowiredMock @AutowiredSpy on class)
- partial mocks (spock sample, mockito sample)
Requirements
Basic requirements to make it running:
- java8
- spring <= 4.3.6
- springboot <= 1.4.4
Required spring modules: spring-context & spring-test
Mockito
mockito-core <= 1.10.x is required and must be provided. Samples with spring-boot
Spock
To get spock mocks running you'll need:
- spock-core 1.1-groovy-2.4
- spock-spring 1.1-groovy-2.4
Installation
Releases
With Mockito as mocks provider
mvn
<dependency>
<groupId>com.pchudzik.springmock</groupId>
<artifactId>springmock-mockito</artifactId>
<version>1.2.0</version>
</dependency>
gradle
testCompile('com.pchudzik.springmock:springmock-mockito:1.2.0')
With Spock as mock provider
mvn
<dependency>
<groupId>com.pchudzik.springmock</groupId>
<artifactId>springmock-spock</artifactId>
<version>1.2.0</version>
</dependency>
gradle
testCompile('com.pchudzik.springmock:springmock-spock:1.2.0')
sample pom.xml with spring-boot
Snapshots
Repository configuration
Add sonatype snapshots repository to repositories list
Maven:
<repositories>
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
Gradle:
repositories {
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots'
}
mavenCentral()
}
Mockito as mocks provider
Include mvn dependency:
<dependency>
<groupId>com.pchudzik.springmock</groupId>
<artifactId>springmock-mockito</artifactId>
<version>1.2.1-SNAPSHOT</version>
</dependency>
Or gradle dependency:
testCompile('com.pchudzik.springmock:springmock-mockito:1.2.1-SNAPSHOT')
Spock as mocks provider
Include mvn dependency:
<dependency>
<groupId>com.pchudzik.springmock</groupId>
<artifactId>springmock-spock</artifactId>
<version>1.2.1-SNAPSHOT</version>
</dependency>
Or gradle dependency:
testCompile('com.pchudzik.springmock:springmock-spock:1.2.1-SNAPSHOT')
Usage
Mock injection infrastructure is the same and is independent to selected mock provider.
Once mock is injected you can use it accordingly to selected mocking library for mockito and for spock
Mocks
To inject mocks just annotate field you want to be initialized and injected with mock using @AutowiredMock and you are good to go
@AutowiredMock AnyService anyService;
@Test
public void should_inject_mock() {
assertTrue(mockingDetails(anyService).isMock());
}
or in spock:
@AutowiredMock AService service
def "should inject mock"() {
given: service.hello() >> "mock"
when: final result = service.hello()
then: result == "mock"
}
You can specify name of the registered mock using name param. Which will result in registering mock with the specific name in the spring context (like in with @Bean#name). If name is not provided bean name will be the same ase the field name on which it is declared.
You can also provide list of aliases for mock using alias attribute.
Sample test case with mockito mocks
Sample test case with spock mocks
Spies
Right now springmock can not create spies on the fly and inject them in the context. In order to spy on the bean it must already be registered in the context. It needs appropriate object to already exist in spring context.
@AutowiredSpy Service service;
@Test
public void should_inject_spy() {
assertTrue(mockingDetails(service).isSpy());
}
or in spock:
@AutowiredSpy Service service
def "should inject spy"() {
when: service.hello()
then: 1 * service.hello() >> "spy!"
}
You can specify name of the bean which should be replaced by created spy using name attribute. if no name is defined then destination bean will be matched field name or by class.
Configuration
Mockito
Annotate @AutowiredMock or @AutowiredSpy field with @MockitoDouble. Examples:
- ShouldParseDoubleResetModeTest
- ShouldConfigureAnswerTest
- ShouldAssignExtraInterfacesToCreatedMockTest
- ShouldConfigureMockSerializableModeTest
- ShouldConfigureVerboseDoubleTest
- ShouldConfigureStubOnlyDoubleTest
- ShouldConfigureInvocationListenerTest
Spock
Annotate @AutowiredMock or @AutowiredSpy field with @SpockDouble. Examples:
- DoubleConstructorArgumentsTest
- DoubleDefaultResponseTest
- GlobalSpockDoubleTest
- SpockDoubleImplementationTest
- StubDoublesTest
- UseObjenesisInDoublesTest
Problems
Please report any problems with the library using Github issues. I'd really appreciate failing test case included in issue description or as PR.
Development
Versions
Setting version is done using script.mvnw/update-versions.groovy. From this script versions are loaded from version.properties and applied on all required projects (root + samples).
To apply versions from property file execute:
./mvnw -P versions-update gplus:execute -N
Deployment
Private key must be imported into pgp.
In order to do the release, release versions must be set in poms and one must execute goal:
SONATYPE_USERNAME=secret_user \
SONATYPE_PASSWORD=secret_password \
./mvnw --settings .mvn/settings.xml -P release clean deploy
Changelog
1.2.0 springmock-spock - 2018.12.03
1.2.0 springmock-mockito - 2018.12.03
1.1.2 springmock-spock - 2017.09.17
- Fixed spy reset code to handle missing beans - #15
- Single bean instance will be replaced by mock/spy without matching name #10
1.1.2 springmock-mockito - 2017.09.17
- Single bean instance will be replaced by mock/spy without matching name #10
1.1.0 springmock-mockito - 2017.09.06
- mocks configuration - @MockitoDouble
- fixed mocks reset in context hierarchy
- optimizations to listener responsible for mock reset between tests methods executions
- class level mocks sample
- mocks and spies can be created and injected into @Configuration classes (mock injection example, spy injection example)
- added possibility to create spies without real object present in context. Word of warning. It will produce partial mock, which might not work as you'd expect it to work and might cause some unexpected failures. In general yous should spy on existing bean instance, unless it is very trivial bean without any fields.
1.1.0 springmock-spock - 2017.09.06
- mocks configuration - @SpockDouble
- optimizations to listener attaching mocks to the currently running specification
- should not fail when executing on mixed code base with spock and junit tests - #11
- class level mocks sample
- mocks and spies can be created and injected into @Configuration classes (mock injection example, spy injection example)
- added possibility to create spies without real object present in context. Word of warning as in mockito it might produce not properly initialized object. In spock you have higher level of control over mocks creation and you can initialize object properly using SpockDouble.constructorArguments see integration test case.
1.0.0 - 2017.07.22
- @AutowiredMock with name and aliases support
- @AutowiredSpy with name and aliases support