Browse Source
Post-processing of mocked beans causes a number of problems: - The mock may be proxied for asynchronous processing which can cause problems when configuring expectations on a mock (gh-6573) - The mock may be proxied so that its return values can be cached or so that its methods can be transactional. This causes problems with verification of the expected calls to a mock (gh-6573, gh-5837) - If the mock is created from a class that uses field injection, the container will attempt to inject values into its fields. This causes problems if the mock is being created to avoid the use of one of those dependencies (gh-6663) - Proxying a mocked bean can lead to a JDK proxy being created (if proxyTargetClass=false) as the mock implements a Mockito interface. This can then cause injection failures as the types don’t match (gh-6405, gh-6665) All of these problems can be avoided if a mocked bean is not post-processed. Avoiding post-processing prevents proxies from being created and autowiring from being performed. This commit avoids post-processing by registering mocked beans as singletons as well as via a bean definition. The latter is still used by the context for type matching purposes. Closes gh-6573, gh-6663, gh-6664pull/6851/head
12 changed files with 235 additions and 122 deletions
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* Copyright 2012-2016 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.mock.mockito; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Beans created using Mockito. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
public class MockitoBeans implements Iterable<Object> { |
||||
|
||||
private final List<Object> beans = new ArrayList<Object>(); |
||||
|
||||
void add(Object bean) { |
||||
this.beans.add(bean); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<Object> iterator() { |
||||
return this.beans.iterator(); |
||||
} |
||||
|
||||
} |
||||
@ -1,91 +0,0 @@
@@ -1,91 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2016 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.mock.mockito; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.exceptions.misusing.UnfinishedVerificationException; |
||||
|
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.annotation.Cacheable; |
||||
import org.springframework.cache.annotation.EnableCaching; |
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager; |
||||
import org.springframework.cache.interceptor.CacheResolver; |
||||
import org.springframework.cache.interceptor.SimpleCacheResolver; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.stereotype.Service; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import static org.mockito.Mockito.reset; |
||||
import static org.mockito.Mockito.times; |
||||
import static org.mockito.Mockito.verify; |
||||
|
||||
/** |
||||
* Test {@link MockBean} when mixed with Spring AOP. |
||||
* |
||||
* @author Phillip Webb |
||||
* @see <a href="https://github.com/spring-projects/spring-boot/issues/5837">5837</a> |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
public class MockBeanWithAopProxyAndNotProxyTargetAwareTests { |
||||
|
||||
@MockBean(proxyTargetAware = false) |
||||
private DateService dateService; |
||||
|
||||
@Test(expected = UnfinishedVerificationException.class) |
||||
public void verifyShouldUseProxyTarget() throws Exception { |
||||
this.dateService.getDate(); |
||||
verify(this.dateService, times(1)).getDate(); |
||||
reset(this.dateService); |
||||
} |
||||
|
||||
@Configuration |
||||
@EnableCaching(proxyTargetClass = true) |
||||
@Import(DateService.class) |
||||
static class Config { |
||||
|
||||
@Bean |
||||
public CacheResolver cacheResolver(CacheManager cacheManager) { |
||||
SimpleCacheResolver resolver = new SimpleCacheResolver(); |
||||
resolver.setCacheManager(cacheManager); |
||||
return resolver; |
||||
} |
||||
|
||||
@Bean |
||||
public ConcurrentMapCacheManager cacheManager() { |
||||
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(); |
||||
cacheManager.setCacheNames(Arrays.asList("test")); |
||||
return cacheManager; |
||||
} |
||||
|
||||
} |
||||
|
||||
@Service |
||||
static class DateService { |
||||
|
||||
@Cacheable(cacheNames = "test") |
||||
public Long getDate() { |
||||
return System.nanoTime(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
/* |
||||
* Copyright 2012-2016 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.mock.mockito; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.scheduling.annotation.Async; |
||||
import org.springframework.scheduling.annotation.EnableAsync; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
|
||||
/** |
||||
* Tests for a mock bean where the mocked interface has an async method. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
public class MockBeanWithAsyncInterfaceMethodIntegrationTests { |
||||
|
||||
@MockBean |
||||
private Transformer transformer; |
||||
|
||||
@Autowired |
||||
private MyService service; |
||||
|
||||
@Test |
||||
public void mockedMethodsAreNotAsync() { |
||||
given(this.transformer.transform("foo")).willReturn("bar"); |
||||
assertThat(this.service.transform("foo")).isEqualTo("bar"); |
||||
} |
||||
|
||||
private interface Transformer { |
||||
|
||||
@Async |
||||
String transform(String input); |
||||
|
||||
} |
||||
|
||||
private static class MyService { |
||||
|
||||
private final Transformer transformer; |
||||
|
||||
MyService(Transformer transformer) { |
||||
this.transformer = transformer; |
||||
} |
||||
|
||||
public String transform(String input) { |
||||
return this.transformer.transform(input); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@EnableAsync |
||||
static class MyConfiguration { |
||||
|
||||
@Bean |
||||
public MyService myService(Transformer transformer) { |
||||
return new MyService(transformer); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
/* |
||||
* Copyright 2012-2016 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.mock.mockito; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
|
||||
/** |
||||
* Tests for a mock bean where the class being mocked uses field injection. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
public class MockBeanWithInjectedFieldIntegrationTests { |
||||
|
||||
@MockBean |
||||
private MyService myService; |
||||
|
||||
@Test |
||||
public void fieldInjectionIntoMyServiceMockIsNotAttempted() { |
||||
given(this.myService.getCount()).willReturn(5); |
||||
assertThat(this.myService.getCount()).isEqualTo(5); |
||||
} |
||||
|
||||
private static class MyService { |
||||
|
||||
@Autowired |
||||
private MyRepository repository; |
||||
|
||||
public int getCount() { |
||||
return this.repository.findAll().size(); |
||||
} |
||||
|
||||
} |
||||
|
||||
private interface MyRepository { |
||||
|
||||
List<Object> findAll(); |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue