简体   繁体   English

Spring 引导@Autowired 在单元测试用例中不工作

[英]Spring boot @Autowired not working in unit test case

As I understand that if we use spring stereotypes then we don't need to use new keyword to create an instance.据我了解,如果我们使用 spring 构造型,那么我们不需要使用 new 关键字来创建实例。 Spring manages that for us and provide us with the beans at runtime. Spring 为我们管理并在运行时为我们提供 bean。

And in order for Spring to inject those beans we need to use @Autowired annotation where we want Spring to inject that bean.为了让 Spring 注入那些 bean,我们需要在我们希望 Spring 注入那个 bean 的地方使用@Autowired注释。 Below I have a very simple class where I am using @Component so that spring manages that.下面我有一个非常简单的 class,我在其中使用@Component ,以便 spring 管理它。 This class has one List which I am initializing with my own responsibility and then a small method which does some logic.这个 class 有一个我自己负责初始化的列表,然后是一个执行一些逻辑的小方法。

@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. java.lang.NullPointerException当它尝试调用parseStrings方法时,这意味着它无法在运行时注入正确的初始化 bean。

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.在 class 上使用 spring 原型时是否有必要添加构造函数(我在这里使用 lombok 注释)。

Spring Autowire if you run the test case with SpringRunner . Autowire如果您使用SpringRunner运行测试用例,则自动装配。 So modify the test class as follows.所以修改测试class如下。

@RunWith(SpringRunner.class)
class ParserTest {

}

To answer your second question, No, it is not necessary to add no-argument constructor unless you also have a parameterised constructor in the same class.要回答您的第二个问题,不,没有必要添加no-argument constructor ,除非您在同一个 class 中也有parameterised constructor函数。 In that case you need to explicitly add a no-arg constructor.在这种情况下,您需要显式添加一个无参数构造函数。

I don't see any mock created so why you are using @RunWith(MockitoJUnitRunner.class) ?我没有看到创建任何模拟,那么为什么要使用@RunWith(MockitoJUnitRunner.class)

I've seen as well answers recommending the use of @SpringBooTest .我也看到了推荐使用@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.这也意味着不涉及 mocking。 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.如果您的解析器没有引用任何其他 Bean(需要模拟),那么您就是在进行简单的单元测试。

@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"));

    }

Why so you even need MockitoJUnitRunner here?为什么你甚至需要 MockitoJUnitRunner ? The Parser has no dependencies.解析器没有依赖关系。 A simple initialization in the test will be enough.在测试中进行简单的初始化就足够了。 Just inialize the Parser instead of using an annotation.只需初始化解析器而不是使用注释。 @SpringBootTest is meant for integration tests. @SpringBootTest用于集成测试。 It brings in the Spring context and makes your unit test slow & bulky.它引入了 Spring 上下文,使您的单元测试变得缓慢而庞大。

SpringBoot2,you can use the annotation: @SpringBootTest to do unit test. SpringBoot2,可以使用注解: @SpringBootTest进行单元测试。

just like below case:就像下面的情况:

@SpringBootTest
class DemoApplicationTests {
   
    @Test
    void contextLoads() {
    }

}

This should work:这应该有效:

@SpringBootTest
@RunWith(SpringRunner.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"));

    }
}

In my case the class was not declared public在我的例子中,class没有公开

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM