嘲笑在Spring Boot测试中使用Mockito返回的MapperFacade

huangapple go评论81阅读模式
英文:

Mocking MapperFacade return in Spring Boot Test with Mockito

问题

我还没有看到有人对这个特定问题给出解决方法。

我有一个服务类,该类由一个仓库(repository)和一个 Orika MapperFacade 构建而成。在测试中,我正在准备一个由仓库调用返回的实体(Entities)列表。我的 doReturn(testList).when(testRepository).findAllBy... 似乎正在起作用。我的实际结果列表包含了我在模拟列表中指定的相同数量的元素(.size()),但是这些值都是 null。我对 Spring Boot 还相当陌生,对 Mockito 更是全新。我目前在测试中使用一个返回使用 MapperFactory 创建的 MapperFacade 的 Bean,并定义了几个类映射。目前我在测试中使用 @Spy 来处理我的 MapperFacade,并且可以通过严格断言列表的大小来传递测试。我理解可能是我需要对 MapperFacade 的行为进行 @Mock 处理,尽管它被用于在服务类中迭代列表。不确定如何在测试中实现这一点。我可以构建另一个 DTO 列表,该列表通常会从迭代实体的循环中返回,但我对 Mockito 语法还不熟悉,也不确定如何运行那个返回操作。

当我尝试从列表的元素中记录或断言 .getAnyValue 时,我会得到一个空指针异常,但是当我在安排的列表中添加或删除元素时,列表的大小会发生变化。

非常感谢任何提供的信息。

服务类

public class FightService {
    private FightRepository repository;
    private MapperFacade mapper;

    @Autowired
    public FightService(FightRepository r, MapperFacade m) {
        this.repository = r;
        this.mapper = m;
    }

    public List<FightDTO> getFightsByWinRound(int winRound){
        List<FightEntity> entities = repository.findAllByWinRound(winRound);
        List<FightDTO> returnVal = new ArrayList<>();
        for(FightEntity e: entities){
            FightDTO dto = mapper.map(e, FightDTO.class);
            returnVal.add(dto);
        }
        return returnVal;
    }
}

服务测试

@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class FightServiceTest{

    @Spy
    private MapperFacade mapperFacade;

    @Mock
    private FightRepository testRepository;

    @InjectMocks
    private FightService systemUnderTest;

    @Test
    public void testGetFightsByWinRound_ScenarioA() throws Exception{
        //安排

        List<FightEntity> testList = new ArrayList<>();
        FightEntity fightA = new FightEntity();
        fightA.setFighter1("A");
        fightA.setWinRound(15);
        testList.add(fightA);
        FightEntity fightB = new FightEntity();
        fightB.setFighter1("B");
        fightB.setWinRound(15);
        testList.add(fightB);
        FightEntity fightC = new FightEntity();
        fightC.setFighter1("C");
        fightC.setWinRound(15);
        testList.add(fightC);

        doReturn(testList).when(testRepository).findAllByWinRound(15);

        //行动
        List<FightDTO> actual = systemUnderTest.getFightsByWinRound(15);

        //断言
        Assert.assertThat(actual.size(), is(3));
        // 我会添加 Assert.assertThat(actual.get(0).getFighter1(), is("A")) ,但这是空指针异常出现的地方。

        //验证
    }
}

注意:上面的翻译只包括代码部分,其他部分已省略。

英文:

I haven't seen this particular question answered in a way that's resolving my issue.

I have a service class that is constructed with a repository and an Orika MapperFacade. In testing, I'm arranging a list of Entities returned by the repository call. my doReturn(testList).when(testRepository).findAllBy... seems to be working. My actual result list contains the same amount of elements (.size()) I've specified in my mocked list, however the values are all null. I'm fairly new to Spring Boot, and definitely new to Mockito. I'm currently using a bean that returns a MapperFacade created with a MapperFactory and has several class maps defined. Right now I'm using a @Spy for my MapperFacade in test, and can pass based strictly on asserting that the size of the lists is the same. I understand it might be that I need to @Mock the behavior or the MapperFacade instead, although it's being used to iterate over a list in the service class. Not positive how to implement that in test. I could build another list of DTO's that would generally be returned from a loop iterating through the entities, but I'm new to Mockito grammar and not sure how I'd run that return.

I get a NullPointerException when trying to log or assert on a .getAnyValue from an element of the list, but the size of the list changes when I add or remove elements in the arranged list.

Any info appreciated.

Service class

public class FightService {
    private FightRepository repository;
    private MapperFacade mapper;

    @Autowired
    public FightService(FightRepository r, MapperFacade m) {
        this.repository = r;
        this.mapper = m;


    }

    public List&lt;FightDTO&gt; getFightsByWinRound(int winRound){

        List&lt;FightEntity&gt; entities = repository.findAllByWinRound(winRound);
        List&lt;FightDTO&gt; returnVal = new ArrayList&lt;&gt;();
        for(FightEntity e: entities){
            FightDTO dto = mapper.map(e, FightDTO.class);
            returnVal.add(dto);
        }
        return returnVal;
    }
}

Service Test

@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class FightServiceTest{

    @Spy
    private MapperFacade mapperFacade;

    @Mock
    private FightRepository testRepository;

    @InjectMocks
    private FightService systemUnderTest;




    @Test
    public void testGetFightsByWinRound_ScenarioA() throws Exception{
        //Arrange

        List&lt;FightEntity&gt; testList = new ArrayList&lt;&gt;();
        FightEntity fightA = new FightEntity();
        fightA.setFighter1(&quot;A&quot;);
        fightA.setWinRound(15);
        testList.add(fightA);
        FightEntity fightB = new FightEntity();
        fightB.setFighter1(&quot;B&quot;);
        fightB.setWinRound(15);
        testList.add(fightB);
        FightEntity fightC = new FightEntity();
        fightC.setFighter1(&quot;C&quot;);
        fightC.setWinRound(15);
        testList.add(fightC);

        doReturn(testList).when(testRepository).findAllByWinRound(15);

        

        //Act

        List&lt;FightDTO&gt; actual = systemUnderTest.getFightsByWinRound(15);


        //Assert

        Assert.assertThat(actual.size(), is(3));
        // I would be adding Assert.assertThat(actual.get(0).getFighter1(), is(&quot;A&quot;)) , but this is where the NPE arises.
    


        //Verify
    }
}

答案1

得分: 1

这对于以下工作:

@InjectMocks
private ServiceClass serviceClass;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    factory = new DefaultMapperFactory.Builder().build();
    when(mapper.getMapperFacade()).thenReturn(factory.getMapperFacade());
    // 对于自定义映射
    factory.classMap(Source.class, Dest.class).customize(new CustomMapper())
            .byDefault().register();
}

您可以在 https://github.com/elaatifi/orika/blob/master/tests/src/main/java/ma/glasnost/orika/test/converter/NumericConvertersTestCase.java#L113 查看一些内部测试。

英文:

This worked for

@InjectMocks
private ServiceClass serviceClass;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    factory = new DefaultMapperFactory.Builder().build();
    when(mapper.getMapperFacade()).thenReturn(factory.getMapperFacade());
    // In case of custom mapping
    factory.classMap(Source.class, Dest.class).customize(new CustomMapper())
            .byDefault().register();
}

You can check some internal tests at https://github.com/elaatifi/orika/blob/master/tests/src/main/java/ma/glasnost/orika/test/converter/NumericConvertersTestCase.java#L113

huangapple
  • 本文由 发表于 2020年9月26日 04:18:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/64070863.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定