0

I am trying to test a method, but when my test method calls the actual method, due to @Value field present , the actual method always receives the value defined under @Value field i.e. null. You can have a look at the code for actual method and the test method below:

Actual method

public class IndexService {

    @Value("${elasticsearch.index}")
    private String index;

    public boolean index(String id, String json, String index) {
        try {
            createIndex();
            return true;
        } catch (IOException e) {
            log.warn("Exception in indexing data {}", e.getMessage());
        }
        return false;
    }
   private void createIndex() throws IOException {
        CreateIndexRequest request = new CreateIndexRequest(index);
    }
}

Below is my test method:

@Test
    public void IndexServiceIndex() throws IOException {
        CreateIndexRequest request1 = new CreateIndexRequest(index);
        request1.source("{\"name\":true}",XContentType.JSON);
        Mockito.when(indicesClient.create(request1,RequestOptions.DEFAULT))
       .thenReturn(createIndexResponse);
        Boolean indexser = indexService.index("65","{\"name\":molly}","1");
}

Below is CreateIndexRequest class method:

public CreateIndexRequest(String index) {
        if (index == null) {
            throw new IllegalArgumentException("The index name cannot be null.");
        } else {
            this.index = index;
        }
    }

What happening is, when my test method calls the actual method indexService.index("65","{\"name\":molly}","1");, then the control goes to the actual method, and the private method createIndex is injecting index value which is defined above as @Value("${elasticsearch.index}") private String index;. and hence in CreateIndexRequest method , it always evaluates to null and throws exception IllegalArgumentException("The index name cannot be null.").

I tried using ReflectionTestUtils.setField but the required dependency of org.springframework.test.util.ReflectionTestUtils is not there in my project. Is there any other way to mock @Value field?

Gregory Javis
  • 105
  • 1
  • 4
  • 10

1 Answers1

1

You simply don't. Using fields injection in general is discauraged because it makes testing code more complicated than it can be. To test whatever you try to test, use either

  1. Constructor injection - you can @Value on constructor params, and it will be possible to put test value via constructor
  2. setter injection - annotate setter method with @Value. It will work exactly the same in the container, and how to use it in tests is obvious
  3. Use @TestProperties - but this will fix the values for the whole test class
  4. Use reflection - this allows you to even mutate final fields, however if it comes to AOP and proxies, this might not simply work

and probably many others. I think that 1 and 2 are the most viable methods.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99