29

I am new to JUnit and automated testing and really want to get into automating my tests. This is a Spring Boot application. I have used Java Based Annotation style instead of XML based configuration.

I have a test class in which I'd like to test a method which retrieves a response based on a users' input.

Testing class:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest(){

  @Autowired
  private SampleClass sampleClass;

  @Test
  public void testInput(){

  String sampleInput = "hi";

  String actualResponse = sampleClass.retrieveResponse(sampleInput);

  assertEquals("You typed hi", actualResponse);

  }
}

Inside my "SampleClass" I have autowired a bean like this.

@Autowired
private OtherSampleClass sampleBean;

Inside my "OtherSampleClass" I have annotated a method like so:

@Bean(name = "sampleBean")
public void someMethod(){
....
}

The issue I'm having is when I try to run the test without the @RunWith and @SpringBootTest annotations when I try to run the test my variables annotated @Autowired are null. And when I try to run the test with those annotations RunWith & SpringBootTest then I get an

IllegalStateException caused by BeanCreationException: Error creating bean with name "sampleBean" AND failure to load application context caused by BeanInstantiationException.

The code works 'properly' when I try to use it as a user would so I can always test this way but I think automated tests would be good for the longevity of the program.

I have used the Spring Boot Testing Docs to assist me in this.

Mehraj Malik
  • 14,872
  • 15
  • 58
  • 85
alwaysStuckJava
  • 359
  • 1
  • 3
  • 10
  • Please add your `SampleClass`. – Mehraj Malik Jan 05 '18 at 12:33
  • 2
    Methods annotated with `@Bean` should return an object, namely the new Spring Bean. – Roland Weisleder Jan 05 '18 at 12:37
  • Spring injects your autowired beans. If you don't run with the spring runner there's nothing there to inject things so the members remain at their default values (null). Please show more of the exception when you run with spring. It's likely a classpath or property-not-found fail as the root cause. – Andy Brown Jan 05 '18 at 16:50

3 Answers3

13

The following config works for me.

File: build.gradle

testCompile("junit:junit:4.12")
testCompile("org.springframework.boot:spring-boot-starter-test")

File: MYServiceTest.java

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest(classes = Application.class,
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
public class MYServiceTest {

    @Autowired
    private MYService myService;

    @Test
    public void test_method() {
        myService.run();
    }
}
Eddy
  • 3,623
  • 37
  • 44
-4

It's best to keep Spring out of your unit tests as much as possible. Instead of Autowiring your bean just create them as a regular object

OtherSampleClass otherSampleClass = mock(OtherSampleClass.class);
SampleClass sampleClass = new SampleClass(otherSampleClass);

But for this you need to use the Constructor injection instead of Field Injection which improves testability.

Replace this

@Autowired
private OtherSampleClass sampleBean;

With this

private OtherSampleClass sampleBean;

@Autowired
public SampleClass(OtherSampleClass sampleBean){
    this.sampleBean = sampleBean;
}

Take a look at this answer for an other code example

Glenn Van Schil
  • 1,059
  • 3
  • 15
  • 33
  • 2
    Testing with mock objects is not ideal thing. With spring boot test and modern testing frameworks rest-assured,spring web clients..it is not required to mock things, And top of the question regarding why auto-wiring not working, not about how to test classes. – Yogi Jan 05 '18 at 13:06
  • 2
    @Yogi This is true in case you are testing controllers, making Integration tests and E2E tests, but for unit tests you should avoid spring as much as possible because it creates much overhead – Glenn Van Schil Jan 05 '18 at 13:09
-5

No need to inject (@Autowired private SampleClass sampleClass;) your actual class which you are testing, and remove SpringBootTest annotation,
SpringBootTest annotation used for integration test cases.
find the following code will help you.

@RunWith(SpringRunner.class)
public class SampleTest(){

  private SampleClass sampleClass;
AdamIJK
  • 615
  • 2
  • 12
  • 22
  • How is this supposed to be an answer to a question that is about _how_ to do `@Autowired`? – mapto May 14 '20 at 06:57