如何在春季服务中模拟映射映射器输出?

发布于 2025-01-19 09:38:08 字数 1925 浏览 3 评论 0原文

我有使用映射映射器(Custommapstruct -Mapper)的春季服务(MyService):

@Service
public class MyService {

    private final ClassA classA;
    private final ClassB classB;
    /*
    other private fields declarations...
    */

    private CustomMapstructMapper customMapstructMapper = Mappers.getMapper(CustomMapstructMapper.class);

    //MyService constructor

    public MyService(final ClassA classA, etc...) {

        this.classA = classA;
        //etc...

    }

    public ServiceOutput mainMethod(some parameters) {

        //some business logic


        MyMapperOutput myMapperOutput = customMapstructMapper.map(MapperParameter parameter);

        ServiceOutput serviceOutput = some business logic with myMapperOutput;

        return serviceOutput;

    }

} 

我想单元测试MyService(我使用Junit 5),并模拟我的Custmapsstrumpstructmapper 输出,而无需在测试期间调用真实映射器执行。我已经有另一个测试类,该类特定于Custompaps -Mapper中测试所有自定义映射。

因此,我有一个测试课:

@ExtendWith(MockitoExtension.class)
class MyServiceTest {

    @InjectMocks
    private MyService myService;

    @Mock
    private CustomMapstructMapper customMapstructMapper;

    @Mock
    private MyMapperOutput myMapperOutput;

    @Test
    void testMyService() {
        /*
        Some mocks creation ..
        */

        Mockito.when(myMapperOutput.getSomeField()).thenReturn("Some value");
        Mockito.when(customMapstructMapper.map(Mockito.any(MapperParameter.class))).thenReturn(myMapperOutput);

        ServiceOutput serviceOutput = myService.mainMethod(some parameters);

        /*
        Some assertions on serviceOutput
        */

    }

} 

当我运行测试时,我的Mapper Custommaps -Mapperimpl的实现在MyService中被调用,而不是我的模拟。 由于某些字段没有启动,因此在我的映射器中抛出了NullPoInterException。 我试图通过实现我的映射映射器创建一个模拟:

@Mock private CustomMapstructMapperImpl customMapstructMapper;

但是我得到了相同的结果。

我在做什么错?

I have a spring service (MyService) that uses a mapstruct mapper (CustomMapstructMapper) :

@Service
public class MyService {

    private final ClassA classA;
    private final ClassB classB;
    /*
    other private fields declarations...
    */

    private CustomMapstructMapper customMapstructMapper = Mappers.getMapper(CustomMapstructMapper.class);

    //MyService constructor

    public MyService(final ClassA classA, etc...) {

        this.classA = classA;
        //etc...

    }

    public ServiceOutput mainMethod(some parameters) {

        //some business logic


        MyMapperOutput myMapperOutput = customMapstructMapper.map(MapperParameter parameter);

        ServiceOutput serviceOutput = some business logic with myMapperOutput;

        return serviceOutput;

    }

} 

I want to unit test MyService (I am using Junit 5) and mock my CustomMapstructMapper output without calling the real mapper during the test execution. I already have another test class that specificly test all the custom mappings in CustomMapstructMapper.

So I have this test class :

@ExtendWith(MockitoExtension.class)
class MyServiceTest {

    @InjectMocks
    private MyService myService;

    @Mock
    private CustomMapstructMapper customMapstructMapper;

    @Mock
    private MyMapperOutput myMapperOutput;

    @Test
    void testMyService() {
        /*
        Some mocks creation ..
        */

        Mockito.when(myMapperOutput.getSomeField()).thenReturn("Some value");
        Mockito.when(customMapstructMapper.map(Mockito.any(MapperParameter.class))).thenReturn(myMapperOutput);

        ServiceOutput serviceOutput = myService.mainMethod(some parameters);

        /*
        Some assertions on serviceOutput
        */

    }

} 

When I run my test, the implementation of my mapper customMapstructMapperImpl is called in MyService, not my mock.
A NullPointerException is thrown in my mapper because some fields are not initiated.
I have tried to create a mock with the implementation of my mapstruct mapper :

@Mock private CustomMapstructMapperImpl customMapstructMapper;

but I get the same result.

What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

掩于岁月 2025-01-26 09:38:08

您没有利用春季框架和对其进行映射支持。

在您的服务更改中:

private CustomMapstructMapper customMapstructMapper = Mappers.getMapper(CustomMapstructMapper.class);

则会

@Autowired
private CustomMapstructMapper customMapstructMapper;

如果您尚未使用映射器,

@Mapper( componentModel = "spring" )

导致生成的映射器具有@component从弹簧框架上注释,并且可以自动使用。这。

进行这些更改后,您提供测试模拟的方法应该有效。

You're not taking advantage of the spring framework and mapstruct support for it.

in your service change:

private CustomMapstructMapper customMapstructMapper = Mappers.getMapper(CustomMapstructMapper.class);

into

@Autowired
private CustomMapstructMapper customMapstructMapper;

If you don't have it yet at your mapper use

@Mapper( componentModel = "spring" )

This will cause the generated mapper to have the @Component annotation from the spring framework, and it becomes possible to auto-wire this.

After making these changes your method of supplying a mock for testing should work.

随波逐流 2025-01-26 09:38:08

下面的代码正常工作。所以也许还有其他事情发生了。您的代码示例还不够完整。


@ExtendWith(MockitoExtension.class)
public class TestForService {

    @InjectMocks
    private Service service;

    @Mock
    private Mapper mapper;

    @Test
    public void test_service() {
        System.out.println("test_service start");
        Mockito.when(mapper.doSomeTh()).thenReturn("mock mapper doSomeTh");
        String result = service.service();
        System.out.println("test_service end, result: " + result);
    }

    static class Service {
        private Mapper mapper = Mapper.getMapper();

        public String service() {
            System.out.println("Service.service");
            return mapper.doSomeTh();
        }

        public void setMapper(Mapper mapper) {
            this.mapper = mapper;
            System.out.println("Service.setMapper: " + mapper);
        }
    }

    static class Mapper {

        public String doSomeTh() {
            System.out.println("Mapper.doSomeTh");
            return "mapper end";
        }

        public static Mapper getMapper() {
            System.out.println("Mapper.getMapper");
            return null;
        }
    }
}

结果:

Mapper.getMapper
Service.setMapper: mapper
test_service start
Service.service
test_service end, result: mock mapper doSomeTh

The code below works correctly. So maybe something else happened. Your code example is not quite complete.


@ExtendWith(MockitoExtension.class)
public class TestForService {

    @InjectMocks
    private Service service;

    @Mock
    private Mapper mapper;

    @Test
    public void test_service() {
        System.out.println("test_service start");
        Mockito.when(mapper.doSomeTh()).thenReturn("mock mapper doSomeTh");
        String result = service.service();
        System.out.println("test_service end, result: " + result);
    }

    static class Service {
        private Mapper mapper = Mapper.getMapper();

        public String service() {
            System.out.println("Service.service");
            return mapper.doSomeTh();
        }

        public void setMapper(Mapper mapper) {
            this.mapper = mapper;
            System.out.println("Service.setMapper: " + mapper);
        }
    }

    static class Mapper {

        public String doSomeTh() {
            System.out.println("Mapper.doSomeTh");
            return "mapper end";
        }

        public static Mapper getMapper() {
            System.out.println("Mapper.getMapper");
            return null;
        }
    }
}

result:

Mapper.getMapper
Service.setMapper: mapper
test_service start
Service.service
test_service end, result: mock mapper doSomeTh
浮华 2025-01-26 09:38:08

在这里简单的方法:
只需在MyService中添加package-Provate setter方法

// for testing only
void CustomMapstructMapper setCustomMapstructMapper(CustomMapstructMapper mapper) {
    this.customMapstructMapper = mapper;
}

,然后在测试代码中注入模拟的custommapsstructmapper

@Test
void testMyService() {
    /*
    Some mocks creation ..
    */

    Mockito.when(myMapperOutput.getSomeField()).thenReturn("Some value");
    Mockito.when(customMapstructMapper.map(Mockito.any(MapperParameter.class))).thenReturn(myMapperOutput);

    myService.setCustomMapstructMapper(customMapstructMapper); // inject your mocked customMapstructMapper here

    ServiceOutput serviceOutput = myService.mainMethod(some parameters);

    /*
    Some assertions on serviceOutput
    */

}

A simpler way here:
Just add a package-private setter method into your MyService

// for testing only
void CustomMapstructMapper setCustomMapstructMapper(CustomMapstructMapper mapper) {
    this.customMapstructMapper = mapper;
}

and inject your mocked CustomMapstructMapper in test code

@Test
void testMyService() {
    /*
    Some mocks creation ..
    */

    Mockito.when(myMapperOutput.getSomeField()).thenReturn("Some value");
    Mockito.when(customMapstructMapper.map(Mockito.any(MapperParameter.class))).thenReturn(myMapperOutput);

    myService.setCustomMapstructMapper(customMapstructMapper); // inject your mocked customMapstructMapper here

    ServiceOutput serviceOutput = myService.mainMethod(some parameters);

    /*
    Some assertions on serviceOutput
    */

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文