user5459039
user5459039

Reputation:

Use of ReflectionTestUtils.setField() in Junit testing

I am new in JUnittesting so i have a question. Can anyone please tell me why we use ReflectionTestUtils.setField() in our Junit testing with example.

Upvotes: 23

Views: 96322

Answers (5)

Pramod S. Nikam
Pramod S. Nikam

Reputation: 4539

One more Use Case:

As a best practice we externalised many properties that we want change in application when thwty are subject to change. Such as: URL's , endpoint and many other properties in application properties like below:

kf.get.profile.endpoint=/profile
kf.get.clients.endpoint=clients

and then these config we can use it in application like below using @Value annotation:

  @Value("${kf.get.clients.endpoint}")
  private String clientEndpoint

but these values we cannot easily set in unit tests because for encapsulation purpose we should be keep these values as private. therefore whenevver when we write unit test , we get NullPointerException because Spring cannot inject @value similarly as @Autowired does. ( at least at the moment , I dont know alternative. ) so to avoid that we can use ReflectionTestUtils to inject externalised properties. like below:

ReflectionTestUtils.setField(targetObject,"clientEndpoint","lorem");

Upvotes: 7

Margarita
Margarita

Reputation: 13

ReflectionTestUtils.setField is used is various contexts. But the most common scenario is when you have a class and inside that, there are attributes with private access, and you want to test this class.

So a possible solution can be using ReflectionTestUtils like in the example below:

public class BBVAFileProviderTest {

    @Mock
    private BBVAFileProvider bbvaFileProvider;

    @Before
    public void setup() throws Exception {
        bbvaFileProvider = new BBVAFileProvider(payoutFileService, bbvaFileAdapter, bbvaCryptographyService, amazonS3Client, providerRequestService, payoutConfirmationService);
        ReflectionTestUtils.setField(this.bbvaFileProvider, "bbvaClient", this.bbvaClient);
    }

    // ...

}

In this example can you see, that ReflectionTestUtils.setField is used to set the value to the private field because it doesn't have a setter method.

Upvotes: -1

Patrick
Patrick

Reputation: 12734

As mentioned in the comment, the java docs explain the usage well. But I want to give you also a simple example.

Let's say you have an Entity class with private or protected field access and no provided setter method.

@Entity
public class MyEntity {

   @Id
   private Long id;

   public Long getId(Long id){
       this.id = id;
   }
}

In your test class, you cannot set an id of your entity because of the missing setter method.

Using ReflectionTestUtils.setField you are able to do that for testing purpose:

ReflectionTestUtils.setField(myEntity, "id", 1);

The Parameters are described:

public static void setField(Object targetObject,
                            String name,
                            Object value)
Set the field with the given name on the provided targetObject to the supplied value.
This method delegates to setField(Object, String, Object, Class), supplying null for the type argument.

Parameters:
targetObject - the target object on which to set the field; never null
name - the name of the field to set; never null
value - the value to set

But give it a try and read the docs.

Upvotes: 32

Naveen Kumar
Naveen Kumar

Reputation: 11

Thank you for above discussions, the below part can also contribute in writing the unit tests by reading the properties from application-test.properties.

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TestPropertySource("classpath:application-test.properties")
public class FileRetrivalServiceTest {

@Value ("${fs.local.quarantine.directory}")
private String localQuarantineDirectory;

@Value ("${fs.local.quarantine.wrong.directory}")
private String localQuarantineWrongDirectory;

@Value ("${fs.local.quarantine.tmp.directory}")
private String localQuarantineTmpDirectory;

@Value ("${fs.local.keys.file}")
private String localKeyFile;
private FileRetrivalService fileRetrivalService;

@Before
public void setUp() throws Exception {
    fileRetrivalService = new FileRetrivalServiceImpl();
    ReflectionTestUtils.setField(fileRetrivalService, "keyFile", localKeyFile);
}

@Test
public void shouldRetrieveListOfFilesInQuarantineDirectory() {
    // given
    ReflectionTestUtils.setField(fileRetrivalService, "quarantineDirectory", localQuarantineDirectory);

    // when
    List<IcrFileModel> quarantineFiles = fileRetrivalService.retrieveListOfFilesInQuarantineDirectory();

    // then
    assertNotNull(quarantineFiles);
    assertEquals(quarantineFiles.size(), 4);
    }
}

Upvotes: 1

brice jiang
brice jiang

Reputation: 21

it's very useful when we want to write unit test, such as:

class A{
   int getValue();
}

class B{
   A a;
   int caculate(){
       ...
       int v = a.getValue();
       ....
   }
}

class ServiceTest{
   @Test
   public void caculateTest(){
       B serviceB = new B();
       A serviceA = Mockito.mock(A.class);
       Mockito.when(serviceA.getValue()).thenReturn(5);
       ReflectionTestUtils.setField(serviceB, "a", serviceA);
   } 
}

Upvotes: 2

Related Questions