0

I use spring boot 2.3.2 with mapstruct.

In a service class I have a mapper who have an autowired annotation.

@Service
public BillingService{

    private BillingRepository billingRepository;


    @Autowired
    private  BillingMapper billingMapper;   


    @Autowired
    public BillingService (BillingRepository billingRepository){
        this.billingRepository=billingRepository;
    }

    public void getBilling(Long billingId){
        ....
        billingMapper.convertTo(...);
    }

}


@RunWith(MockitoJUnitRunner.class)
public class BillingServiceTest{
    @Mock
    BillingRepository billingRepository;

    private BillingService bilingService;

    @Spy
    private BillingMapper billingMapper = Mappers.getMapper(BillingMapper.class);

    @BeforeEach
    public void setup(){
        MockitoAnnotations.initMocks(this);
        billingService = new BillingService();
    }

    @Test
    public void testGetBilling(){

        List<Billing> billings = new ArrayList<>();
        ...

        List<BillingPayload> payloads = new ArrayList<>();

        when(billingMapper.convertTo(billings)).thenReturn(payloads);     

        bilingService.getBilling(1l);  
    }

}

@Mapper(componentModel="spring")
public interface BillingMapper{
    ...
}

When I debug and I'm stuck in getBilling method in BillingService Class, billingMapper is alway null;

robert trudel
  • 5,283
  • 17
  • 72
  • 124

1 Answers1

0

You are using very strange configuration. First of all you have method returning BillingService that doesn't specify any return value so this would not even compile. I suggest following way:

@Service
public BillingService{

    private final BillingRepository billingRepository;
    private final BillingMapper billingMapper;

    // constructor with bean injection
    public BillingService(final BillingRepository billingRepository,
                          final BillingMapper billingMapper) {
        this.billingRepository = billingRepository;
        this.billingMapper = billingMapper;
    }

    public void getBilling(Long billingId){
        ....
        billingMapper.convertTo(...);
    }

}

Then you can configure your test like following:

@RunWith(SpringJUnit4ClassRunner.class)
public class BillingServiceTest {

    @Spy private BillingMapper billingMapper = Mappers.getMapper(BillingMapper.class);
    @MockBean private BillingRepository billingRepository;
    @Autowired private BillingService billingService;

    @TestConfiguration
    static class BillingServiceTestContextConfiguration {
        @Bean public BillingService billingService() {
            return new BillingService(billingRepository, billingMapper);
        }
    }

    @Test
    public void testGetBilling(){
        List<Billing> billings = new ArrayList<>();
        ...
        List<BillingPayload> payloads = new ArrayList<>();
        when(billingRepository.findById(1L)).thenReturn(); // someResult
        when(billingMapper.convertTo(billings)).thenReturn(payloads);
        bilingService.getBilling(1l);  
    }
}

@Mapper(componentModel="spring")
public interface BillingMapper{
    ...
}

Similiar configuration should work. Main problem is that you are mixing @Autowired with setter/constructor injection (don't know since your weird method inside BillingService. Also dont know why you use @Spy annotation when you are tryning to Mock interface. @Spy is used to mock actual instance, while @Mock is mocking Class type. I would stick with @MockBean private BillingMapper billingMapper instead if BillingMapper is specified as Bean in your application.

Norbert Dopjera
  • 741
  • 5
  • 18
  • strange method was my constructor with error, I don't created any bean manually for BillingMapper. Get same error, tested with spy, mock, mockbean..... Tested via a controller take less time – robert trudel Aug 10 '20 at 17:34