ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – 对调用静态方法的类进行单元测试

2019-06-08 16:50:44  阅读:744  来源: 互联网

标签:java unit-testing static-methods easymock google-guava-cache


我试图对一个类’A’进行单元测试,该类调用类’B’的静态方法.类’B’本质上具有google guava缓存,其在给定密钥的情况下从缓存中检索值(Object),或者使用服务适配器将对象加载到缓存中(在缓存未命中的情况下).服务适配器类又具有其他自动连接依赖项来检索对象.

这些是用于说明目的的类:

A级

public class A {
    public Object getCachedObject(String key) {
        return B.getObjectFromCache(key);
    }
}

B级

public class B {

    private ServiceAdapter serviceAdapter;

    public void setServiceAdapter(ServiceAdapter serAdapt) {
        serviceAdapter = serAdapt;
    } 

    private static final LoadingCache<String, Object> CACHE = CacheBuilder.newBuilder()
                .maximumSize(100) 
                .expireAfterWrite(30, TimeUnit.MINUTES)
                .build(new MyCacheLoader());

    public static Object getObjectFromCache(final String key) throws ExecutionException {
        return CACHE.get(warehouseId);
    }

    private static class MyCacheLoader extends CacheLoader<String, Object>  {

        @Override
        public Object load(final String key) throws Exception {
            return serviceAdapter.getFromService(key)
        }
    }
}

服务适配器类

public class ServiceAdapter {
        @Autowired
        private MainService mainService

        public Object getFromService(String key) {
            return mainService.getTheObject(key);
        }
    }

我能够成功地进行集成测试,并从缓存中获取(或加载)该值.但是,我无法为A类编写单元测试.这是我尝试过的:

A级单元测试

@RunWith(EasyMocker.class)
public class ATest {
    private final static String key = "abc";
    @TestSubject
    private A classUnderTest = new A();

    @Test
    public void getCachedObject_Success() throws Exception {
        B.setServiceAdapter(new ServiceAdapter());
        Object expectedResponse = createExpectedResponse(); //some private method 
        expect(B.getObjectFromCache(key)).andReturn(expectedResponse).once();
        Object actualResponse = classUnderTest.getCachedObject(key);
        assertEquals(expectedResponse, actualResponse);
    }
}

当我运行单元测试时,它在ServiceAdapter类中失败并出现NullPointerException,其中调用:mainService.getTheObject(key).

如何在单元测试类A时模拟ServiceAdapter的依赖性.我不应该只关心类A具有的直接依赖性,即. B.

我确信我做的事情从根本上是错误的.我该如何为A级编写单元测试?

解决方法:

您现在知道为什么静态方法被认为是单元测试的不良做法,
因为他们使嘲弄几乎不可能,尤其是如果他们是有状态的.

因此,将B静态方法重构为一组非静态公共方法更为实际.

A类应该通过构造函数或setter注入获得B类实例.在你的ATest中,你然后使用类B的模拟实例化A类,并根据你的测试用例返回你想要的任何东西,并根据你的断言来确定它.

通过这样做,你真的测试了单元,它最终应该是A类的公共接口.(这也是我喜欢一个类在理想世界中只有一个公共方法的原因.)

关于你的具体例子:B的模拟也不应该关心它自己的依赖.您目前在测试中写道:

 B.setServiceAdapter(new ServiceAdapter());       

你在ATest.不在BTest. ATest应该只有B的模拟,因此不需要传递ServiceAdapter的实例.

你应该只关心A的公共方法是如何表现的,并且鉴于B公共方法的某些反应,这可能会改变.

我也觉得奇怪的是,你想要测试的方法基本上只是B的包装器.也许这在你的情况下有意义但这也暗示我你可能想要在A中注入一个Object而不是B的实例.

如果你不想在模仿地狱中迷失方向,那么每个类的公共方法就越少,从而尽可能减少依赖关系.我努力争取每班三个依赖,并在特殊场合允许最多五个. (每个依赖项可能会对模拟开销产生巨大影响.)

如果您有太多依赖项,当然可以将某些部分移动到其他/新服务.

标签:java,unit-testing,static-methods,easymock,google-guava-cache
来源: https://codeday.me/bug/20190608/1198918.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有