Git Product home page Git Product logo

springmock's Introduction

springmock

Build Status Coverage Status

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

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

Samples with spring-boot

Installation

Releases

With Mockito as mocks provider

mvn

Maven Central

<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

Maven Central

<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

sample build.gradle

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:

Spock

Annotate @AutowiredMock or @AutowiredSpy field with @SpockDouble. Examples:

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

  • register field name as double alias - #9
  • added support for springboot2.1 - #17

1.2.0 springmock-mockito - 2018.12.03

  • register field name as double alias - #9
  • added support for springboot2.1 - #17

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

springmock's People

Contributors

pchudzik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

springmock's Issues

support for java7

A lot of code is written in java8 because it was the easiest one. Maybe support for java7 will be good idea?

mockito spies are not resetted

see
com.pchudzik.springmock.mockito.spring.MockitoMockResetTestExecutionListener
com.pchudzik.springmock.mockito.spring.MockitoMockResetTestExecutionListenerTest

mocks are handled properly but spies are completely ignored but should be handled in the same way as mocks

Determine beanName just like what `@MockBean` do

Spring Boot's @MockBean determines beanName automatically:

	private String determineBeanName(String[] existingBeans, SpyDefinition definition,
			BeanDefinitionRegistry registry) {
		if (StringUtils.hasText(definition.getName())) {
			return definition.getName();
		}
		if (existingBeans.length == 1) {
			return existingBeans[0];
		}
		return determinePrimaryCandidate(registry, existingBeans,
				definition.getTypeToSpy());
	}

So that the mock will automatically override existing beans without raising NoUniqueBeanDefinitionException like:

No qualifying bean of type 'com.cht.commons.security.login.UserRegistry' available: expected single matching bean but found 2: userRegistry,userRegistryMock

spy should be distinguished from mock if they are both of the same class

If mock is of the same class as spy and both are injected into specification infrastructure doesn't distinguish them and injects mock in place of spy (or other way around).

Sample test case:
'''
@AutowiredSpy
MyService spy;

@AutowiredMock
MyService mock;

@Test
public void spy_should_be_distinguishable_from_mock_of_the_same_class() {
	assertNotSame(spy, mock);
}

@Test
public void should_distinguish_mock() {
	assertSame(aMock, mock);
}

@Test
public void should_distinguish_spy() {
	assertSame(aSpy, spy);
}

'''

Detailed test case: com.pchudzik.springmock.infrastructure.test.SpyAndMockOfTheSameClassShouldBeDistinguishable (ignored right now)

Question about WebMvcTest support

Hi Paweł,

Great library. I'm going to use it for mocking dependencies for Spring MVC controller tests.
Did you try it with @ WebMvcTest ?

@WebMvcTest(MyController)
class MyControllerTest extends Specification {

  @Autowired
  MockMvc mockMvc

  @AutowiredMock
  MyService myService

}

now i'm having exception:

java.lang.NullPointerException
	at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1612)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078)
	at com.pchudzik.springmock.spock.spring.MockAttachingTestExecutionListener.tryToGetBean(MockAttachingTestExecutionListener.java:122)
	at com.pchudzik.springmock.spock.spring.MockAttachingTestExecutionListener.beforeTestMethod(MockAttachingTestExecutionListener.java:62)
	at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:269)

Do I understand correctly that in current version(1.0.0) it is not supported?

inject mocks by name

see test case com.pchudzik.springmock.infrastructure.test.name.DoubleNameShouldBeUsedAsQualifier
it should be possible to inject different mocks without the @qualifier annotation

currently it fails with:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.pchudzik.springmock.infrastructure.test.name.DoubleNameShouldBeUsedAsQualifier$MockService' available: expected single matching bean but found 2: mock1,mock2

Non-spock tests failing with IllegalArgumentException

My project has a large mix of Spock and Junit tests, the spock tests use a mix of Mockito and Spock mocks, the JUnit tests just use Mockito, since adding this library all of my non spock tests fail with the following error:

Stacktrace
java.lang.IllegalArgumentException: MockAttachingTestExecutionListener can be applied only for spock specifications
	at com.pchudzik.springmock.spock.spring.MockAttachingTestExecutionListener.beforeTestMethod(MockAttachingTestExecutionListener.java:48)
	at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:269)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)

Is there anyway to globally turn the listener off, and only add it to the tests where I'm making use of the library? (until such time as I can actually convert the whole code base)

Null Pointer exception when names don't match up

If the mocks variable name doesn't match the bean name, it can't find the bean to mock, and it falls over with a NPE. I can get round it by making the names match, but seems a bit inflexible.

for example:
@AutowiredSpy ProjectionService spy

java.lang.NullPointerException
	at org.spockframework.mock.MockUtil.asMock(MockUtil.java:54)
	at org.spockframework.mock.MockUtil.attachMock(MockUtil.java:68)
	at com.pchudzik.springmock.spock.spring.MockAttachingTestExecutionListener.beforeTestMethod(MockAttachingTestExecutionListener.java:59)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.