5

i have a @Service that I am trying to mock in an Unit Test but i get a null value so far. In the application class I specify what are the scanBasePackages. Do I have to do this in a different way? Thanks.

This is my service class that implements an interface:

@Service
public class DeviceService implements DeviceServiceDao {

private List<Device> devices;

@Override
public List<Device> getDevices(long homeId) {
    return devices;
}

}

This is my unit test.

public class SmartHomeControllerTest {

    private RestTemplate restTemplate = new RestTemplate();
    private static final String BASE_URL = “..”;

    @Mock
    private DeviceService deviceService;

@Test
public void getHomeRegisteredDevices() throws Exception {

    Device activeDevice = new DeviceBuilder()
            .getActiveDevice(true)
            .getName("Alexa")
            .getDeviceId(1)
            .getHomeId(1)
            .build();
    Device inativeDevice = new DeviceBuilder()
            .getInactiveDevice(false)
            .getName("Heater")
            .getDeviceId(2)
            .getHomeId(1)
            .build();

    UriComponentsBuilder builder = UriComponentsBuilder
            .fromUriString(BASE_URL + "/1/devices");

    List response = restTemplate.getForObject(builder.toUriString(), List.class);

    verify(deviceService, times(1)).getDevices(1);
    verifyNoMoreInteractions(deviceService);
}
Gabi Radu
  • 1,107
  • 2
  • 16
  • 35

5 Answers5

3

You have to use a Spring test runner if you want to load and use a Spring context during tests execution.
You don't specify any runner, so it uses by default the runner of your test API. Here is probably JUnit or TestNG (the runner using depends on the @Test annotation specified).
Besides, according to the logic of your test, you want to invoke the "real" REST service :

List response = restTemplate.getForObject(builder.toUriString(), 
List.class);

To achieve it, you should load the Spring context and load the Spring Boot container by annotating the test with @SpringBootTest.

If you use a Spring Boot context, to mock the dependency in the Spring context, you must not use @Mock from Mockito but @MockBean from Spring Boot.
To understand the difference between the two, you may refer to this question.

Note that if you are using the @SpringBootTest annotation, a TestRestTemplate is automatically available and can be autowired into your test.
But beware, this is fault tolerant. It may be suitable or not according to your tests.

So your code could look like :

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SmartHomeControllerTest {

    private static final String BASE_URL = “..”;

    @Autowired
    private TestRestTemplate restTemplate;

    @MockBean
    private DeviceService deviceService;

    @Test
    public void getHomeRegisteredDevices() throws Exception {        
       ...
    }

As a side note, avoid using raw type as List but favor generic type.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • I didn't modify this part. I focused on the injection issue. But you probably right. I also note that the OP doesn't make any assertion on the retrieved `List`. – davidxxx Oct 14 '17 at 19:53
  • I have added the SpringBootTest and MockBean annotation, but now i get a null context: "Caused by: java.lang.IllegalArgumentException: Cannot load an ApplicationContext with a NULL 'contextLoader'. Consider annotating your test class with @ContextConfiguration or @ContextHierarchy." – Gabi Radu Oct 15 '17 at 07:57
1
@RunWith(SpringJUnit4ClassRunner.class)  
@SpringBootTest(classes = NotificationApplication.class)  
public class EmailClientImplTest {  
...  
}  

And also add the needed properties/configs in
/src/test/resources/application.yml

Good luck!

0

I figured it out, I am using Mockito and used that to annotate my test class. This allowed me to get a mock of the service class that i am trying to use.

@RunWith(MockitoJUnitRunner.class)
 public class SmartHomeControllerTest {..
     @Mock
     private DeviceService deviceService;
  }
Gabi Radu
  • 1,107
  • 2
  • 16
  • 35
-1

Try with @InjectMock instead of @Mock

MGPJ
  • 1,062
  • 1
  • 8
  • 15
-2

You should run your test with spring boot runner

Alexander.Furer
  • 1,817
  • 1
  • 16
  • 24