Spring boot @Autowired not working in unit test case

Tags: , , , ,



As I understand that if we use spring stereotypes then we don’t need to use new keyword to create an instance. Spring manages that for us and provide us with the beans at runtime.

And in order for Spring to inject those beans we need to use @Autowired annotation where we want Spring to inject that bean. Below I have a very simple class where I am using @Component so that spring manages that. This class has one List which I am initializing with my own responsibility and then a small method which does some logic.

@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
public class Parser {

    private List<String> strList = new ArrayList<>();

    public void parseStrings(final String[] strs) {

        Arrays.stream(strs)
                .map(String::toLowerCase)
                .filter(str -> str.length() > 8)
                .filter(str -> str.endsWith("sam"))
                .forEach(sam1 ->  { strList.add(sam1); });
    }

}

I also wrote one unit test to test that and here is that.

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.jupiter.api.Assertions.*;
@RunWith(MockitoJUnitRunner.class)
class ParserTest {

   @Autowired
   private Parser parser;

    @Test
    void parseStrings() {
        String str[] = {"abcsamsam", "abcsyjhgfed abdul sam","abcAhgbkgdjhul samad", "abcabjhgdulsamsam", "sa"};
        parser.parseStrings(str);

        assertTrue(parser.getStrList().size() == 3);
        assertTrue(parser.getStrList().get(0).equalsIgnoreCase("abcsamsam"));

    }
}

The test fails with

java.lang.NullPointerException when it tries to call parseStrings method which means that its not able to inject a proper initialized bean at run time.

Can some one guide that what I am missing? Is it necessary to add constructors (which here I am doing using lombok annotations) when using spring stereotypes on a class.

Answer

I don’t see any mock created so why you are using @RunWith(MockitoJUnitRunner.class)?

I’ve seen as well answers recommending the use of @SpringBooTest. This annotation loads the whole context of your application basically for integration tests in order to integrate different layers of the application. That also means no mocking is involved. Do you really need that? (I don’t think so since you’re talking about unit test)

If your parser doesn’t reference any other Bean (which need to be mocked), then you are in case of simple unit test.

@RunWith(SpringRunner.class) // you can even removed it 
class ParserTest {

private Parser parser;

@Before
public void setUp() {
     parser = new Parser();

}

    @Test
    void parseStrings() {
        String str[] = {"abcsamsam", "abcsyjhgfed abdul sam","abcAhgbkgdjhul samad", "abcabjhgdulsamsam", "sa"};
        parser.parseStrings(str);

        assertTrue(parser.getStrList().size() == 3);
        assertTrue(parser.getStrList().get(0).equalsIgnoreCase("abcsamsam"));

    }


Source: stackoverflow