Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice - Setting a field without setters in a unit test

Let's say you have the following class you would like to test:

public class SomeService {
  public String someMethod(SomeEntity someEntity) {
    return someEntity.getSomeProperty();
  }
}

The SomeEntity looks like this:

public class SomeEntity {
  private String someProperty;

  public getSomeProperty() {
    return this.someProperty;
  }
}

The assertion you would like to do can be the following:

String result = someService.someMethod(someEntity);

assertThat(result).isEqualTo("someValue");

How can you make this test work?

1) Add a setter for 'someProperty' in the SomeEntity class. I don't think this a good solution because you don't change production code to make your tests work.

2) Use ReflectionUtils to set the value of this field. Test would look like this:

 public class TestClass {
      private SomeService someService;

        @Test
          public void testSomeProperty() {
            SomeEntity someEntity = new SomeEntity();
            ReflectionTestUtils.setField(someEntity, "someProperty", "someValue");

            String result = someService.someMethod(someEntity);

            assertThat(result).isEqualTo("someValue");
          }
}

3) You create an inner class in your test class that extends the SomeEntity class and adds the setter for this field. However, for this to work you will also need to change the SomeEntity class because the field should become 'protected' instead of 'private'. Test class might look like this:

public class TestClass {
  private SomeService someService;

  @Test
  public void testSomeProperty() {
   SomeEntityWithSetters someEntity = new SomeEntityTestWithSetters();
    someEntity.setSomeProperty("someValue");

    String result = someService.someMethod(someEntity);

    assertThat(result).isEqualTo("someValue");
  }


  public class SomeEntityWithSetters extends SomeEntity {
   public setSomeProperty(String someProperty) {
     this.someProperty = someProperty;
   } 
  }
}

4) You use Mockito to mock SomeEntity. Seems fine if you only need to mock only one property in the class, but what if you need to mock like 10 properties are so. The test might look like this:

public class TestClass {
  private SomeService someService;

  @Test
  public void testSomeProperty() {
    SomeEntity someEntity = mock(SomeEntity.class);
    when(someEntity.getSomeProperty()).thenReturn("someValue");

    String result = someService.someMethod(someEntity);

    assertThat(result).isEqualTo("someValue");
  }
}
like image 942
wvp Avatar asked Feb 27 '15 06:02

wvp


People also ask

Do I need to unit test getters and setters?

Unit tests are there to test the behaviour of your code, in an expressive and meaningful way, and getters/setters are only a means to an end. If you tests use the getters/setters to achieve their goal of testing the "real" functionality, then that's good enough.

Should I unit test every method?

Every behavior should be covered by a unit test, but every method doesn't need its own unit test. Many developers don't test get and set methods, because a method that does nothing but get or set an attribute value is so simple that it is considered immune to failure.

What is the easiest method to write a unit test in spring?

java. Spring Boot provides an easy way to write a unit test for Rest controller. With the help of SpringJUnit4ClassRunner and MockMVC, a web application context can be created to write unit test for Rest controller. First, we add the necessary annotations to our test class as in the previous test.


2 Answers

you can set the value using reflection. It doesn't need any change in production code.

ReflectionTestUtils.setField(YourClass.class, "fieldName", fieldValue);

like image 58
krmanish007 Avatar answered Sep 28 '22 10:09

krmanish007


You can add a setter with default (package private) scope.

like image 33
BetaRide Avatar answered Sep 28 '22 09:09

BetaRide