gpt4 book ai didi

java - 我们可以在测试服务本身的同时模拟服务中的方法吗?

转载 作者:行者123 更新时间:2023-11-30 11:18:32 25 4
gpt4 key购买 nike

我正在做一个项目,我使用 MyBatis 注释作为持久性框架。因此,我必须为“映射器”创建一个接口(interface),并在服务中编写映射器,例如:

class XYZServiceImpl{

public XYZMapper getXYZMapper(){
return SessionUtil.getSqlSession().getMapper(XYZMapper.class)
}

}

现在,在使用 Mockito 对服务进行单元测试时,我正在尝试为映射器注入(inject)模拟。但是由于我在 XYZService 的实例中注入(inject)模拟,如何模拟服务本身的方法,在这种情况下 getXYZMapper() 是我试图 stub 的。虽然我有一个在服务中创建实例 XYZMapper 的解决方案,而不是像上面的代码那样按需调用:

  Class XYZServiceImpl{

XYZMapper mapper;

public void useXYZMapper(){
mapper = SessionUtil.getSqlSession().getMapper(XYZMapper.class);
}

}

但这会带来很多代码更改(当然我可以重构)但是有没有一种方法可以在不更改代码的情况下实现?

此外,在类中拥有映射器实例的“纯粹”方式是什么方法 1 在性能方面优于方法 2?

编辑:这里 XYZMapper 是一个接口(interface)。像这样的东西:

public interface XYZMapper{
@Select("SELECT * FROM someclass WHERE id = #{id}")
public SomeClass getSomeClass(int id);

}

编辑:我面临着类似的情况,但有一个差异,即我有一个我确实想测试的服务,比如 XYZServiceImpl。现在它有一个方法 getXYZDetails() ,它在服务中处理了很多业务逻辑。现在,如果 getXYZDetails 如下所示:

public XYZDetails getXYZDetails(int id){

XYZDetails details = new XYZDetails();

details.set1Details(fetchSet1Details(id));

//Perform some business logic

details.set2Details(fetchSet2Details(id));

if(details.set2Details() != null){
for(int i = 0; i < details.set2Details().size(); i++){
flushTheseDetails(i);
}
}
.
.

}

请注意,fetchSet1Details()、fetchSet2Details()、flushTheseDetails 分别是公共(public)服务、公共(public)服务和私有(private)服务。

我想知道一种可以在测试 getXYZDetails() 时模拟/ stub 这些方法的方法,从而使我能够

最佳答案

您可以使用多个选项。

注入(inject)依赖

这只适用于像 getXYZMapper 这样的简单方法,当方法只返回你对象的外部依赖时。这可能需要创建新的 XYZServiceImpl 实例,例如,如果映射器绑定(bind)到每个请求打开的连接。

在对象中封装方法行为

获得类似结果的另一种方法是使用 factoryservice locator像这样:

public class XYZServiceImpl {
public XYZServiceImpl(XYZMapperFactory mapperFactory) {
this.mapperFactory = mapperFactory;
}

public XYZMapper getXYZMapper() {
return mapperFactory.getMapper();
}
}

这将使您可以轻松地将测试中的工厂替换为返回模拟映射器的实现。

类似的方法可用于其他方法 fetchSet1DetailsfetchSet2DetailsflushTheseDetails,将它们移动到其他类。如果该方法包含复杂的(并且可能是松散相关的)逻辑,那么它是一个很好的候选者,可以移动到单独的类中。想一想这些方法的作用。通常你可以将它们的一些重要的和不相关的部分移动到其他类或类,这使得模拟它们更容易。

子类

这不是 recommended但在遗留代码中,有时作为临时解决方案非常有用。

在您的测试子类中,您在测试下进行分类并覆盖您需要的方法:

@Test
public void someTest() {
XYZServiceImpl sut = new XYZServiceImpl() {
public XYZMapper getXYZMapper() {
return mapperMock;
}
public Whatever fetchSet1Details() {
return whateverYouNeedInTest;
}
}

sut.invokeMethodUnderTest();
}

您可能唯一需要做的就是将私有(private)方法的访问修饰符更改为 package-private 或 protected,以便您可以覆盖它们。

spy

这个方法也在discouraged但你可以使用 mockito spy :

XYZServiceImpl realService = new XYZServiceImpl();
XYZServiceImpl spy = Mockito.spy(realService);

when(spy.fetchSet1Details()).thenReturn(whaeveryouneed);
when(spy.getXYZMapper()).thenReturn(mockMapper);

spy.methodUnderTest();

关于java - 我们可以在测试服务本身的同时模拟服务中的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23823463/

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