Spring 启动@Autowired 在单元测试用例中不工作
Spring boot @Autowired not working in unit test case
据我了解,如果我们使用 spring 构造型,那么我们不需要使用 new 关键字来创建实例。 Spring 为我们管理并在 运行 时间为我们提供 bean。
为了让 Spring 注入那些 bean,我们需要在我们希望 Spring 注入那个 bean 的地方使用 @Autowired
注释。
下面我有一个非常简单的 class,我在其中使用 @Component
,以便 spring 进行管理。这个 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); });
}
}
我还写了一个单元测试来测试它,就是这个。
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"));
}
}
测试失败
java.lang.NullPointerException
当它尝试调用 parseStrings
方法时,这意味着它无法在 运行 时间注入正确的初始化 bean。
有人可以指导我缺少什么吗?
在 class.
上使用 spring 构造型时是否有必要添加构造函数(我在这里使用 lombok 注释)
Spring Autowire
如果你 运行 测试用例 SpringRunner
。所以修改测试class如下
@RunWith(SpringRunner.class)
class ParserTest {
}
为了回答你的第二个问题,
不,没有必要添加 no-argument constructor
,除非您在同一个 class 中也有一个 parameterised constructor
。在这种情况下,您需要显式添加无参数构造函数。
SpringBoot2,可以使用注解:@SpringBootTest做单元测试
就像下面的案例:
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
}
}
我没有看到创建任何模拟,所以你为什么要使用 @RunWith(MockitoJUnitRunner.class)
?
我也看到了推荐使用 @SpringBooTest
的答案。此注解加载应用程序的整个上下文,主要用于集成测试,以便集成应用程序的不同层。这也意味着不涉及模拟。你真的需要吗? (我不这么认为,因为你在谈论单元测试)
如果你的解析器没有引用任何其他 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"));
}
这应该有效:
@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"));
}
}
为什么你在这里甚至需要 MockitoJUnitRunner?解析器没有依赖关系。在测试中进行简单的初始化就足够了。只需初始化解析器而不是使用注释。 @SpringBootTest
用于集成测试。它引入 Spring 上下文并使您的单元测试缓慢且庞大。
在我的例子中,class 未 声明为 public
据我了解,如果我们使用 spring 构造型,那么我们不需要使用 new 关键字来创建实例。 Spring 为我们管理并在 运行 时间为我们提供 bean。
为了让 Spring 注入那些 bean,我们需要在我们希望 Spring 注入那个 bean 的地方使用 @Autowired
注释。
下面我有一个非常简单的 class,我在其中使用 @Component
,以便 spring 进行管理。这个 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); });
}
}
我还写了一个单元测试来测试它,就是这个。
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"));
}
}
测试失败
java.lang.NullPointerException
当它尝试调用 parseStrings
方法时,这意味着它无法在 运行 时间注入正确的初始化 bean。
有人可以指导我缺少什么吗? 在 class.
上使用 spring 构造型时是否有必要添加构造函数(我在这里使用 lombok 注释)Spring Autowire
如果你 运行 测试用例 SpringRunner
。所以修改测试class如下
@RunWith(SpringRunner.class)
class ParserTest {
}
为了回答你的第二个问题,
不,没有必要添加 no-argument constructor
,除非您在同一个 class 中也有一个 parameterised constructor
。在这种情况下,您需要显式添加无参数构造函数。
SpringBoot2,可以使用注解:@SpringBootTest做单元测试
就像下面的案例:
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
}
}
我没有看到创建任何模拟,所以你为什么要使用 @RunWith(MockitoJUnitRunner.class)
?
我也看到了推荐使用 @SpringBooTest
的答案。此注解加载应用程序的整个上下文,主要用于集成测试,以便集成应用程序的不同层。这也意味着不涉及模拟。你真的需要吗? (我不这么认为,因为你在谈论单元测试)
如果你的解析器没有引用任何其他 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"));
}
这应该有效:
@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"));
}
}
为什么你在这里甚至需要 MockitoJUnitRunner?解析器没有依赖关系。在测试中进行简单的初始化就足够了。只需初始化解析器而不是使用注释。 @SpringBootTest
用于集成测试。它引入 Spring 上下文并使您的单元测试缓慢且庞大。
在我的例子中,class 未 声明为 public