Home > Net >  How to inject configuration properties to a service in Spring testing?
How to inject configuration properties to a service in Spring testing?

Time:10-21

So I have a configuration properties bean

@Data
@ConfigurationProperties(prefix = "amount")
public class AmountProperties {
    private BigInteger minimum;
    private BigInteger maximum;
}

This configuration properties bean is used in a service

@Slf4j
@Data
@Service
@RequiredArgsConstructor
public class AmountService {
    private final OtherService otherService;

    private final AmountProperties amountProperties;
}

Now in testing I have a test class like this

@Slf4j
@ExtendWith(value = SpringExtension.class)
@EnableConfigurationProperties(value = AmountProperties.class)
@TestPropertySource("classpath:amount-test.properties")
public class CashOutServiceTest {
    @Mock
    private OtherService otherService;

    @Autowired
    private CashOutProperties cashOutProperties;

    @InjectMocks
    private AmountService amountService;

    @Test
    void a() {
        assertNotNull(amountProperties);
        log.debug("{}", amountProperties);
    }

    @Test
    void b() {
        assertNotNull(amountService.getAmountProperties());
        log.debug("{}", amountService.getAmountProperties());
    }
}

a test function succeed, but b test function fails. How do I inject amountProperties to amountService?

CodePudding user response:

You need to create a real AmountService class because you want to test it but you need to mock other classes used in AmountService class. Also, you can find mockito documentation says that doesn't mock everything.

@Slf4j
@ExtendWith(value = SpringExtension.class)
@EnableConfigurationProperties(value = AmountProperties.class)
@TestPropertySource("classpath:amount-test.properties")
public class CashOutServiceTest {

    @Mock
    private OtherService otherService;

    @Autowired
    private AmountProperties amountProperties;

    private AmountService amountService;

    @BeforeEach // If you using junit 4 use @Before annotation
    public void init() {
        MockitoAnnotations.openMocks(this);
        amountService = new AmountService(otherService, amountProperties);
    }

    @Test
    void a() {
        assertNotNull(amountProperties);
        log.debug("{}", amountProperties);
    }

    @Test
    void b() {
        assertNotNull(amountService.getAmountProperties());
        log.debug("{}", amountService.getAmountProperties());
    }

}

CodePudding user response:

You mix two approaches (SpringExtension and InjectMocks). If you used SpringExtension - that means spring context will be created (use @MockBean). If you used InjectMocks - that means mocks will be created independently of spring(use @ExtendWith(MockitoExtensions.class)), in this case EnableConfigurationProperties and TestPropertySource will not work for your tested service annotated by @InjectMocks .
My understanding you want delegate creating of 'AmountProperties' by spring in this case please see my example:

@Slf4j
@ExtendWith(value = SpringExtension.class)
@EnableConfigurationProperties(value = AmountProperties.class)
@TestPropertySource("classpath:amount-test.properties")
@MockBean(OtherService.class)
public class CashOutServiceTest {
        
    @Autowired
    AmountProperties amountProperties;

    @Autowired
    AmountService amountService;

    @Test
    void a() {
        assertNotNull(amountProperties);
        log.debug("{}", amountProperties);
    }

    @Test
    void b() {
        assertNotNull(amountService.getAmountProperties());
        log.debug("{}", amountService.getAmountProperties());
    }
}

PS. @MockBean can also be used at the field level if you want to use in a test.

public class CashOutServiceTest {
   @MockBean
   OtherService otherService;
  • Related