gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-31 19:44:08 24 4
gpt4 key购买 nike

我正在尝试对调用类“B”的静态方法的类“A”进行单元测试。 “B”类本质上有一个 google guava 缓存,它在给定键的情况下从缓存中检索值(对象),或者使用服务适配器将对象加载到缓存中(以防缓存未命中)。服务适配器类又具有其他 Autowiring 的依赖项来检索对象。

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

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);
}
}

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

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

我确定我做的事情从根本上是错误的。 A类的单元测试应该怎么写?

最佳答案

你现在知道为什么静态方法被认为是单元测试的坏习惯了,因为他们几乎不可能 mock ,特别是。如果它们是有状态的。

因此,将 B static 方法重构为一组非静态公共(public)方法更为实用。

A 类应该通过构造函数或 setter 注入(inject)来注入(inject) B 类的实例。在你的 ATest 中,你然后用类 B 的模拟实例化类 A,并让它根据你的测试用例返回你喜欢的任何东西,并以此为基础你的断言。

这样做你真正测试了 unit,它最终应该是类 A 的公共(public)接口(interface)。(这也是为什么我喜欢一个类在一个类中只有一个公共(public)方法的原因理想世界。)


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

 B.setServiceAdapter(new ServiceAdapter());       

您在 ATest 中。不在 BTest 中。 ATest 应该只有 Bmock,因此不需要传递 ServiceAdapter 的实例。

您只需要关心 A 的公共(public)方法的行为方式,这可能会根据 B 的公共(public)方法的某些响应而改变。

我还觉得奇怪的是,您想要测试的方法基本上只是 B 的包装器。也许这对您的情况有意义,但这也暗示我您可能想要注入(inject)一个 Object 而不是 B 的实例。

如果你不想迷失在模拟 hell 中,那么每个类的公共(public)方法越少越好,这反过来又尽可能减少依赖性。我争取每个类(class)有 3 个依赖关系,在特殊情况下允许最多 5 个依赖关系。 (每个依赖项都可能对模拟开销产生巨大影响。)

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

关于java - 对调用静态方法的类进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39922637/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com