当前位置:  开发笔记 > Android > 正文

Spring bean在单元测试环境中重新定义

如何解决《Springbean在单元测试环境中重新定义》经验,为你挑选了4个好方法。

我们将Spring用于我的应用程序目的,并使用Spring Testing框架进行单元测试.但是我们遇到一个小问题:应用程序代码从类路径中的位置列表(xml文件)加载Spring应用程序上下文.但是当我们运行单元测试时,我们希望一些Spring bean是模拟而不是完整的实现类.此外,对于某些单元测试,我们希望一些bean成为模拟,而对于其他单元测试,我们希望其他bean成为模拟,因为我们正在测试应用程序的不同层.

所有这些意味着我想重新定义应用程序上下文的特定bean并在需要时刷新上下文.在执行此操作时,我只想重新定义位于一个(或多个)原始xml bean定义文件中的一小部分bean.我找不到一个简单的方法来做到这一点.一直认为Spring是一个测试友好框架的单元,所以我必须在这里遗漏一些东西.

你有什么想法怎么做吗?

谢谢.



1> Michael Pral..:

我会提出一个自定义的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;
    }
}

如果在指定位置有mock-bean.xml,它们将覆盖"正常"位置中的所有"真实"bean.xml - 您的正常位置可能不同

但是......当应用程序变老时,我永远不会混合模拟和非模拟bean,很难跟踪问题.



2> krosenvold..:

spring被描述为测试友好的原因之一是因为在单元测试中可能很容易只是新的或模拟的东西.

或者我们使用以下设置取得了巨大的成功,我认为它非常接近你想要的,我强烈推荐它:

对于在不同上下文中需要不同实现的所有bean,请切换到基于注释的布线.您可以按原样保留其他人.

实现以下注释集

 
     
     
     
 

然后使用@Repository 注释您的实时实现,使用@StubRepository 注释您的存根实现,以及仅使用@TestScopedComponent存在于单元测试夹具中的任何代码.您可能会遇到需要更多注释的问题,但这些都是一个很好的开始.

如果你有很多spring.xml,你可能需要制作一些基本上只包含组件扫描定义的新的spring xml文件.您通常只需将这些文件附加到常规的@ContextConfiguration列表中.这样做的原因是因为你经常与上下文扫描的不同配置(相信我,你最终做出至少1点以上的注解,如果你在做网络测试,这使得4名相关的组合)

然后你基本上使用了

@ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)

请注意,此安装程序不会让你有存根/实时数据的交替组合.我们尝试了这个,我认为这导致了一个混乱,我不会推荐任何人;)我们要么连接完整的存根集或全套实时服务.

我们主要使用自动连线存根依赖关系测试gui附近的东西,其中依赖通常相当大.在代码的清洁区域,我们使用更常规的单元测试.

在我们的系统中,我们有以下用于组件扫描的xml文件:

用于常规网络制作

仅用存根启动web

用于集成测试(在junit中)

用于单元测试(在junit中)

用于硒网测试(在junit中)

这意味着我们完全有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);
     }


   }
}

我知道测试纯粹主义者会为此而全力以赴.但有时它只是一个非常实用的解决方案,当替代方案真的很难看时,它会变得非常优雅.再次,它通常在那些gui-near区域.



3> Ev0oD..:

使用@InjectedMock注释查看本 教程

它为我节省了很多时间.你刚才用

@Mock
SomeClass mockedSomeClass

@InjectMock
ClassUsingSomeClass service

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

你所有的问题都解决了.Mockito将用模拟替换弹簧依赖注入.我只是自己使用它,效果很好.



4> Daniel Alexi..:

这里列出了一些非常复杂和强大的解决方案.

但是有一种FAR,FAR更简单的方法来完成Stas所要求的内容,它不涉及修改测试方法中除一行代码之外的任何内容.它适用于单元测试和Spring集成测试,适用于自动连接的依赖项,私有和受保护的字段.

这里是:

junitx.util.PrivateAccessor.setField(testSubject, "fieldName", mockObject);


或者,如果你使用的是spring:`org.springframework.test.util.ReflectionTestUtils.setField(testSubject,"fieldName",mockObject);`
假设您可以轻松访问获取注入依赖项的对象.
推荐阅读
echo7111436
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有