0

I am writing unit tests for my services in Spring, Java. I mock all dependencies in a tested class and I instantiate the tested class in a constructor, to which I pass mocked classes. The problem is that the tested class injects properties from .properties file into fields that are inside it (let's say Strings).

I use the standard combination of @PropertySource on a class level and @Value on a field level inside my tested class.

As we know, properties injection fails when class is instantiated through constructor (not as a bean during the Spring Container initialization). How do you deal with such problem?

I've got one solution, though I think it is bad and unsatisfactory, that is: 1. to @Autowire the class under test normally, then replace all its dependencies by using a setter.

I also know about the @TestPropertySource annotation and if I understand correctly, it does not provide a solution and it is only a way to override already existent properties - which is not the case, as we cannot really use any properties.

Thanks for help in advance :)

JacekDuszenko
  • 136
  • 2
  • 11
  • Possible duplicate of https://stackoverflow.com/questions/23162777/how-do-i-mock-an-autowired-value-field-in-spring-with-mockito – Daisy Day Jul 29 '18 at 15:36
  • that part with reflectionTestUtils is interesting, but still, it is not satisfactory to me, as I could just use normal reflection – JacekDuszenko Jul 29 '18 at 15:42

1 Answers1

0

It is rather straight : in your unit test, inject the property in a String field and create the object under test not in the constructor of the test class but in the hook method invoked after the container has loaded the Spring context.
In JUnit 4, you specify this hook method with @Before and in JUnit 5 with @BeforeEach.

It would give something like :

@RunWith(SpringJUnit4ClassRunner.class)
public class FooTest{

    Foo foo;
    @Value("${myProp}") 
    String myProp;

    @BeforeEach
    public void beforeEach(){
       foo = new Foo(myProp);
    }
}

Note that to make your test be executed faster you should load from the Spring context only what your test requires : the environment part.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • But what if I don't want the String property that I've got in my tested class to be in the constructor? I want it to be only accessible in a particular method of my tested class. Well, the context is that this property injected field is just a string that is used to parse some JSON provided to the method before. – JacekDuszenko Jul 29 '18 at 15:40
  • You want to be able to set a field of an object not managed by Spring but you don't want to provide a setter, a param constructor or using reflection ? Not possible in these conditions. If if you want to be really decoupled from Spring in your unit test, do the things all the way. Personally I would not even load the Spring context to load the properties. Or else accept the coupling with Spring in the unit test. – davidxxx Jul 29 '18 at 15:47