Sta*_*tas 51 spring unit-testing spring-test
我们将Spring用于我的应用程序目的,并使用Spring Testing框架进行单元测试.但是我们遇到一个小问题:应用程序代码从类路径中的位置列表(xml文件)加载Spring应用程序上下文.但是当我们运行单元测试时,我们希望一些Spring bean是模拟而不是完整的实现类.此外,对于某些单元测试,我们希望一些bean成为模拟,而对于其他单元测试,我们希望其他bean成为模拟,因为我们正在测试应用程序的不同层.
所有这些意味着我想重新定义应用程序上下文的特定bean并在需要时刷新上下文.在执行此操作时,我只想重新定义位于一个(或多个)原始xml bean定义文件中的一小部分bean.我找不到一个简单的方法来做到这一点.一直认为Spring是一个测试友好框架的单元,所以我必须在这里遗漏一些东西.
你有什么想法怎么做吗?
谢谢.
Mic*_*low 18
我会提出一个自定义的TestClass和一些简单的spring bean.xml位置规则
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath*:spring/*.xml",
"classpath*:spring/persistence/*.xml",
"classpath*:spring/mock/*.xml"})
@Transactional
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DirtiesContextTestExecutionListener.class})
public abstract class AbstractHibernateTests implements ApplicationContextAware {
/**
* Logger for Subclasses.
*/
protected final Logger log = LoggerFactory.getLogger(getClass());
/**
* The {@link ApplicationContext} that was injected into this test instance
* via {@link #setApplicationContext(ApplicationContext)}.
*/
protected ApplicationContext applicationContext;
/**
* Set the {@link ApplicationContext} to be used by this test instance,
* provided via {@link ApplicationContextAware} semantics.
*/
@Override
public final void setApplicationContext(
final ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
Run Code Online (Sandbox Code Playgroud)
如果在指定位置有mock-bean.xml,它们将覆盖"正常"位置中的所有"真实"bean.xml - 您的正常位置可能不同
但是......当应用程序变老时,我永远不会混合模拟和非模拟bean,很难跟踪问题.
kro*_*old 16
spring被描述为测试友好的原因之一是因为在单元测试中可能很容易只是新的或模拟的东西.
或者我们使用以下设置取得了巨大的成功,我认为它非常接近你想要的,我强烈推荐它:
对于在不同上下文中需要不同实现的所有bean,请切换到基于注释的布线.您可以按原样保留其他人.
实现以下注释集
<context:component-scan base-package="com.foobar">
<context:include-filter type="annotation" expression="com.foobar.annotations.StubRepository"/>
<context:include-filter type="annotation" expression="com.foobar.annotations.TestScopedComponent"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
Run Code Online (Sandbox Code Playgroud)
然后使用@Repository 注释您的实时实现,使用@StubRepository 注释您的存根实现,以及仅使用@TestScopedComponent存在于单元测试夹具中的任何代码.您可能会遇到需要更多注释的问题,但这些都是一个很好的开始.
如果你有很多spring.xml,你可能需要制作一些基本上只包含组件扫描定义的新的spring xml文件.您通常只需将这些文件附加到常规的@ContextConfiguration列表中.这样做的原因是因为你经常与上下文扫描的不同配置(相信我,你最终会做出至少1点以上的注解,如果你在做网络测试,这使得4名相关的组合)
然后你基本上使用了
@ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
Run Code Online (Sandbox Code Playgroud)
请注意,此安装程序不会让你有存根/实时数据的交替组合.我们尝试了这个,我认为这导致了一个混乱,我不会推荐任何人;)我们要么连接完整的存根集或全套实时服务.
我们主要使用自动连线存根依赖关系测试gui附近的东西,其中依赖通常相当大.在代码的清洁区域,我们使用更常规的单元测试.
在我们的系统中,我们有以下用于组件扫描的xml文件:
这意味着我们完全有5种不同的系统范围配置,我们可以启动应用程序.由于我们只使用注释,因此弹簧足够快,甚至可以自动连接我们想要连接的单元测试.我知道这是非传统的,但它真的很棒.
完整的集成测试运行完整的实时设置,一两次我决定真正实用,并希望有5条实时接线和一个模拟:
public class HybridTest {
@Autowired
MyTestSubject myTestSubject;
@Test
public void testWith5LiveServicesAndOneMock(){
MyServiceLive service = myTestSubject.getMyService();
try {
MyService mock = EasyMock.create(...)
myTestSubject.setMyService( mock);
.. do funky test with lots of live but one mock object
} finally {
myTestSubject.setMyService( service);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我知道测试纯粹主义者会为此而全力以赴.但有时它只是一个非常实用的解决方案,当替代方案真的很难看时,它会变得非常优雅.再次,它通常在那些gui-near区域.
它为我节省了很多时间.你刚才用
@Mock
SomeClass mockedSomeClass
@InjectMock
ClassUsingSomeClass service
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
Run Code Online (Sandbox Code Playgroud)
你所有的问题都解决了.Mockito将用模拟替换弹簧依赖注入.我只是自己使用它,效果很好.
这里列出了一些非常复杂和强大的解决方案.
但是有一种FAR,FAR更简单的方法来完成Stas所要求的内容,它不涉及修改测试方法中除一行代码之外的任何内容.它适用于单元测试和Spring集成测试,适用于自动连接的依赖项,私有和受保护的字段.
这里是:
junitx.util.PrivateAccessor.setField(testSubject, "fieldName", mockObject);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
52143 次 |
| 最近记录: |