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.
Advertisement
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")); }