gpt4 book ai didi

java - 模拟抽象类的其余部分但调用其中的真实方法?

转载 作者:行者123 更新时间:2023-12-01 11:16:03 26 4
gpt4 key购买 nike

有一些接口(interface)称为 Foo

interface Foo {
void add(Object key, Object value);
Object get(Object key);
void someOtherMethodUnessentialToTesting();
}

测试中有一个名为 MockFoo 的实现,它以“默认”方式实现大多数方法(不执行任何操作,返回 null,基本上只实现它们,以便编译)。然而,它实现了几个来提供真正的功能,它们是插入和读取 Map 的方法。 (如果最后一点不是必需的,我只会使用 Mockito 模拟,甚至不会询问。)

// The current "bad mock"
class MockFoo implements Foo {

Map<Object, Object> map = new ...

@Override
void add(Object key, Object value) {
map.put(key, value);
}

@Override
Object get(Object key) {
map.get(key);
}

@Override
void someOtherMethodUnessentialToTesting()
{}
}

问题是,因为这不是 Mockito 模拟,每次接口(interface)更改时都必须更新测试。是的,人们应该更好地检查以修复他们更改的接口(interface)的所有实现,但在我看来,确实一开始就不应该在测试中实现。

我很困惑如何解决这个问题。我的本能是使其抽象并仅实现那些方法,然后以某种方式模拟它,以便它在需要时调用那些“真正的”方法。我读到 Mockito 有一个用于 stub 的 thenDoRealMethod() ,但这仅用于返回值,因此它不适用于 void 方法。

// My abstract class I was trying to stub somehow
abstract class FooForTest implements Foo {

Map<Object, Object> map = new ...

@Override
void add(Object key, Object value) {
map.put(key, value);
}

@Override
Object get(Object key) {
map.get(key);
}
}
<小时/>

我意识到这可能是一个设计问题,在实际代码中添加 AbstractFoo 可能是最好的(因为 add 和 get 不会真正改变),但我更好奇是否有只需修改测试代码即可一劳永逸地解决此问题。

最佳答案

使用类似 this SO answer 中的技术,您可以使用 CALLS_REAL_METHODS 作为默认答案,或者,正如您所建议的,您可以使用默认答案 (RETURNS_DEFAULTS) 并单独 stub 某些方法来调用您的假方法。因为您希望显示 Mockito 的行为,所以我推荐后者。

void 方法有一个与 thenCallRealMethod 等效的方法:doCallRealMethod。您需要从 do 开始,因为 when(T value) 没有可取的值[并随后忽略]。

abstract class FooForTest implements Foo {

public static Foo create() {
FooForTest mockFoo = mock(FooForTest.class);
mockFoo.map = new HashMap<>();
when(mockFoo.get(any())).thenCallRealMethod();
doCallRealMethod().when(mockFoo).add(any(), any());
return mockFoo;
}

Map<Object, Object> map = new ...

@Override
void add(Object key, Object value) {
map.put(key, value);
}

@Override
Object get(Object key) {
map.get(key);
}
}

如果没有复杂的反射,我想不出有什么方法可以自动让 Mockito 仅针对未实现的方法调用真正的方法。不过,如果您要为此编写答案,则可以通过将其传递到对 mock 的调用中来将其用于所有方法。您还需要在 create 方法中显式初始化字段,因为模拟不是真实的对象,并且不会正确初始化。

另一种选择是使用空方法 stub ,并使用 spy() 代替;这将解决一些初始化问题。

<小时/>

这种技术称为部分模拟,请注意它可以充当 code smell ——具体来说,被测试的类违反了单一职责原则。无论如何,出于所有这些原因,在向广泛实现的接口(interface)添加方法时,您应该非常小心,并考虑使用 AbstractFoo (或完全实现的 FakeFoo)稍后升级。

关于java - 模拟抽象类的其余部分但调用其中的真实方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31812754/

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