Warm tip: This article is reproduced from serverfault.com, please click

Model Mapper works on Live Code but is not working during JUNITs

发布于 2020-11-25 16:12:00

Background

I have a simple SpringBoot application in which I am testing an UPDATE to my Domain Object from a DTO. Naturally - I am using a ModelMapper to convert from DTO->Entity. The issue I am running into is that while the ModelMapper is working perfectly in the live run, its not working during JUNITs. I put a breakpoint in the initBaseModelMapper in my Configuration file during both JUNIT and LIVE runs and the breakpoint hits successfully. But in JUNITS, during the actual mapping - the null values are still being applied to the Domain entity but not during the live run which works perfectly.

Configuration

@Configuration
public class ModelMapperConfiguration {
    @Bean(name = "myEntityMapper")
    public ModelMapper modelMapper() {
        return initBaseModelMapper();
    }
    
    public static ModelMapper initBaseModelMapper() {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setPropertyCondition(Conditions.isNotNull());
        modelMapper.getConfiguration().setSkipNullEnabled(true); // Tried without this as well
        return modelMapper; // Gets hit during LIVE and JUNITS
    }
}

Main Class Method Under Test

public class MyCaseService {
    @Autowired
    @Qualifier("myEntityMapper")
    private ModelMapper modelMapper;

    @Override
    @Transactional
    public @ResponseBody
    MyCaseEntity updateMyCase(
            @Valid final String myCaseId,
            @Valid MyCaseDTO myCase) throws Exception {

        MyCaseEntity existingEntity = entityRepository.find(myCaseId);
        modelMapper.map(myCase, existingEntity);
        return existingEntity;
    }

JUNIT

I put a breakpoint the the ModelConfiguration and I can see it getting Initialized exactly like when the code is running live. However, for some reason, the ModelMapper is IGNORING the skipping of null fields unlike when its running live

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes= {ModelMapperConfiguration.class})
public class MyCaseServiceTest {
    @InjectMocks
    private MyCaseService testSubject;

    @Spy
    @Qualifier("myEntityMapper")
    private ModelMapper modelMapper;
   
    @Before
    public void setUp() {
        // Initialized `testEntityCase` etc with Id etc
    }

    @Test
    public void testUpdate() throws Exception {
        Mockito.when(entityRepository.find(Mockito.any())).thenReturn(testEntityCase);
        
        MyCaseEntity myCase = testSubject.updateMyCase(
                "1", 
                testCaseDTO);
        
        assertEquals(1L, myCase.getId().longValue()); // <- Test Fails with NullPointer. Id becomes null during  JUNIT.
    }
Questioner
Dorian McAllister
Viewed
0
Turo 2020-11-28 16:55:37

One way to overcome theses Problems is to autowire the constructur of MyCaseService instesd of the private member

public class MyCaseService {

    private ModelMapper modelMapper;

    @Autowired 
    MyCaserService(@Qualifier("myEntityMapper") ModelMapper modelMapper) {
        this.modelMapper = modelMapper;
    }

    @Override
    @Transactional
    public @ResponseBody
    MyCaseEntity updateMyCase(
            @Valid final String myCaseId,
            @Valid MyCaseDTO myCase) throws Exception {

        MyCaseEntity existingEntity = entityRepository.find(myCaseId);
        modelMapper.map(myCase, existingEntity);
        return existingEntity;
    }
}

In the Test you can use the Spy to create the Service

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes= {ModelMapperConfiguration.class})
public class MyCaseServiceTest {

    @Spy
    @Qualifier("myEntityMapper")
    private ModelMapper modelMapper;

    private MyCaseService testSubject;
   
    @Before
    public void setUp() {
        testSubject = new MyCaseService(modelMapper);
        // Initialized `testEntityCase` etc with Id etc
    }
...