en Lopes
en Lopes

Reputation: 2123

Junit / Spring Boot mocking classes

I've generated a Spring Boot web application using Spring Initializr, using embedded Tomcat + Thymeleaf template engine, and package as an executable JAR file.

Technologies used :

Spring Boot 1.4.2.RELEASE, Spring 4.3.4.RELEASE, Thymeleaf 2.1.5.RELEASE, Tomcat Embed 8.5.6, Maven 3, Java 8

I have this class I have this junit test class:

@ContextConfiguration(classes={TestPersistenceConfig.class})
@RunWith(SpringRunner.class)
@SpringBootTest
public class JdbcRemoteUnitRepositoryTests {

    @Autowired
    private JdbcRemoteUnitRepository repository;

    @Autowired
    @InjectMocks
    private SmsConfig smsConfig;

    @Autowired
    @InjectMocks
    private NextelSMSSender  smsService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test   
    public void testGetAllUnits() throws DataAccessException, SQLException {        
        Assert.assertTrue(true);
    }

}

the class NextelSMSSender:

@Service("smsService")
public class NextelSMSSender  {

    public final static String OK_STATUS_CODE = "200";

    @Autowired
    SmsConfig smsConfig;
..
}

.

@Configuration
@PropertySource("sms-gateway.properties")
public class SmsConfig {

    @Value("${sms.domainId}")
    private String domainId;

    @Value("${sms.gateway.url}")
    private String gatewayUrl;
..
}

But it seems that is not mocking the objects property, because when I package the app. I got this error:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field smsConfig in com.plats.bruts.NextelSMSSender required a bean of type 'com.plats.bruts.config.SmsConfig' that could not be found.

Action:

Consider defining a bean of type 'com.plats.bruts.config.SmsConfig' in your configuration.

I created a mock bean named TestSmsConfig, tried to add @Bean, but I got a compilation error:

The annotation @Bean is disallowed for this 
 location

    @Configuration
    @Bean
    public class TestSmsConfig {

        @Value("fake.domainId")
        private String domainId;

        @Value("fake.sms.gateway.url")
        private String gatewayUrl;

         ...
}

Upvotes: 2

Views: 1451

Answers (2)

Fernando
Fernando

Reputation: 406

OK, so this is your configuration:

    @Configuration
    @PropertySource("sms-gateway.properties")
    public class SmsConfig {

    @Value("${sms.domainId}")
    private String domainId;

    @Value("${sms.gateway.url}")
    private String gatewayUrl;
..
}

If you want to use that configuration in your test, you should add it to your configuration classes...

@ContextConfiguration(classes={TestPersistenceConfig.class, SmsConfig.class})

And not add it as @Autowired or whatever.

Upvotes: 0

Michael Peacock
Michael Peacock

Reputation: 2104

You're autowiring smsConfig, but you do not appear to provide that @Bean in your test application context.

In addition, you are using @InjectMocks incorrectly - this should be used to inject mock objects into the class under test (your NextelSMSSender class, not SmsConfig).

To resolve, add a @Bean method in your configuration class to provide SmsConfig bean instances.

Replace @InjectMocks from the SmsConfig variable in your test class with @MockBean. SmsConfig is an autowired mock object, and not the class under test.

See Section 41.3.4 - Of the Spring Boot Testing Features for more info:

Spring Boot includes a @MockBean annotation that can be used to define a Mockito mock for a bean inside your ApplicationContext. You can use the annotation to add new beans, or replace a single existing bean definition. The annotation can be used directly on test classes, on fields within your test, or on @Configuration classes and fields. When used on a field, the instance of the created mock will also be injected. Mock beans are automatically reset after each test method.

Upvotes: 1

Related Questions