Java 用Mockito注射DozerBeanMapper

Java 用Mockito注射DozerBeanMapper,java,mockito,dozer,Java,Mockito,Dozer,我在春季服务中使用推土机。如何使用JUnit和Mockito将DozerBeanMapper注入到经过测试的服务中 如果简化,我的java类如下所示: @Service public class UnicornService { private final DozerBeanMapper dozer; @Autowired public UnicornService(DozerBeanMapper dozer) { this.dozer = dozer;

我在春季服务中使用推土机。如何使用JUnit和Mockito将DozerBeanMapper注入到经过测试的服务中

如果简化,我的java类如下所示:

@Service
public class UnicornService {
    private final DozerBeanMapper dozer;

    @Autowired
    public UnicornService(DozerBeanMapper dozer) {
        this.dozer = dozer;
    }

    public UnicornDto convert(Unicorn unicorn) {
        return dozer.map(unicorn, UnicornDto.class);
    }
}
import static com.shazam.shazamcrest.MatcherAssert.assertThat;
import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs;

@RunWith(MockitoJUnitRunner.class)
public class UnicornServiceTest {
    @Mock
    private DozerBeanMapper dozer;
    @InjectMocks
    private UnicornService unicornService;

    @Test
    public void testConvert() throws Exception {
        final Unicorn original = ...
        final UnicornDto expected = ...

        // Execute the method being tested
        final UnicornDto result = unicornService.convert(original);
        // Validation
        assertThat(result, sameBeanAs(expected));
    }
}
使用JUnit 4+Mockito+Hamcrest的测试类如下所示:

@Service
public class UnicornService {
    private final DozerBeanMapper dozer;

    @Autowired
    public UnicornService(DozerBeanMapper dozer) {
        this.dozer = dozer;
    }

    public UnicornDto convert(Unicorn unicorn) {
        return dozer.map(unicorn, UnicornDto.class);
    }
}
import static com.shazam.shazamcrest.MatcherAssert.assertThat;
import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs;

@RunWith(MockitoJUnitRunner.class)
public class UnicornServiceTest {
    @Mock
    private DozerBeanMapper dozer;
    @InjectMocks
    private UnicornService unicornService;

    @Test
    public void testConvert() throws Exception {
        final Unicorn original = ...
        final UnicornDto expected = ...

        // Execute the method being tested
        final UnicornDto result = unicornService.convert(original);
        // Validation
        assertThat(result, sameBeanAs(expected));
    }
}
问题在于模拟的Dozer实例没有按预期映射对象-默认情况下,Mockito存根返回空或空对象。如果我从测试中删除@Mock注释,它会抛出NPE

在DozerBeanMapper对象上使用注释。这将允许您调用该对象的所有常规方法,同时该对象仍由Mockito作为一个mock进行管理,并注入到一个已测试的服务中

@RunWith(MockitoJUnitRunner.class)
public class UnicornServiceTest {
    @Spy
    private DozerBeanMapper dozer;
    @InjectMocks
    private UnicornService unicornService;
    // ...   

我发现的另一个解决方案是重构代码。对我来说,它似乎没有那么吸引人,因为它弊大于利,只是为了编写测试

在服务中通过setter使用注入

@Service
public class UnicornService {
    private DozerBeanMapper dozer;

    @Autowired
    public setDozer(DozerBeanMapper dozer) {
        this.dozer = dozer;
    }

    public UnicornDto convert(Unicorn unicorn) {
        return dozer.map(unicorn, UnicornDto.class);
    }
}
重构测试:

@RunWith(MockitoJUnitRunner.class)
public class UnicornServiceTest {
    @InjectMocks
    private UnicornService unicornService;

    @Before
    public void injectDozer() {
        final DozerBeanMapper dozer = new DozerBeanMapper();
        unicornService.setDozer(dozer);
    }
    // ...

您根本不应该依赖映射器来创建适当的对象,只需要服务调用映射器并返回其结果即可。实际映射应该在映射器的单元测试中进行测试。即

@RunWith(MockitoJUnitRunner.class)
public class UnicornServiceTest {
    @Mock
    private DozerBeanMapper dozer;
    @InjectMocks
    private UnicornService unicornService;

    @Test
    public void testConvert() throws Exception {
        final Unicorn original = mock(Unicorn.class);
        final UnicornDto expected = mock(UnicornDto.class);
        when(dozer.map(original, UnicornDto.class)).thenReturn(expected);

        // Execute the method being tested
        final UnicornDto result = unicornService.convert(original);
        // Validate that the call was delegated to the mapper
        assertThat(result, is(expected));
    }
}

请注意下面的评论:使用真正的间谍应该谨慎,有时,在大多数情况下,这不是您想要设计应用程序的方式。@daniu我考虑到了这一点。正如你所看到的,我提出了两个解决方案。你认为替代方案更好吗?