Spring Boot 单元测试

Posted

技术标签:

【中文标题】Spring Boot 单元测试【英文标题】:Spring Boot Unit Test 【发布时间】:2016-05-28 21:40:22 【问题描述】:

我是弹簧靴的新手。需要一些建议 这是我的单元测试类

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
public class EmployeeRepositoryTest 

@Autowired
protected EmployeeRepository employeeRepository;


@Test
public void insertEmploee()

    Employee employee = new Employee();

    employee.setEmpName("Azad");
    employee.setEmpDesignation("Engg");
    employee.setEmpSalary(12.5f);

    employeeRepository.save(employee);


当我运行它时,我得到异常

java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotationAttributes(Ljava/lang/reflect/AnnotatedElement;Ljava/lang/String;ZZ)Lorg/springframework/core/annotation/AnnotationAttributes;

at org.springframework.test.util.MetaAnnotationUtils$AnnotationDescriptor.<init>(MetaAnnotationUtils.java:290)
at org.springframework.test.util.MetaAnnotationUtils$UntypedAnnotationDescriptor.<init>(MetaAnnotationUtils.java:365)
at org.springframework.test.util.MetaAnnotationUtils$UntypedAnnotationDescriptor.<init>(MetaAnnotationUtils.java:360)
at org.springframework.test.util.MetaAnnotationUtils.findAnnotationDescriptorForTypes(MetaAnnotationUtils.java:191)
at org.springframework.test.util.MetaAnnotationUtils.findAnnotationDescriptorForTypes(MetaAnnotationUtils.java:198)
at 

进程以退出代码 -1 结束

【问题讨论】:

看起来你的依赖有问题(也许你正在混合一些 Spring-Versions)。您能否提供您的依赖项(如果您使用的是 maven 或等效的 gradle 文件,则为 pom.xml)? @MikeBoddin 已解决。你说得对 顺便说一句,如果您在测试中启动 Spring 上下文,它通常不再被视为单元测试。 @luboskrnac 我有兴趣了解更多详情 只是命名/标题是错误的,这更像是一个集成测试而不是实际的单元测试。对于单元测试(当您只需要测试一些代码时),使用SpringJUnit4ClassRunner 运行器可能不是一个好主意,因为它启动整个应用程序并且比不使用运行器慢很多。在这种情况下,您可能会检查是否在数据库中创建了记录,在这种情况下,您正在编写集成测试。 【参考方案1】:

看来您的问题已解决(混合 Spring 依赖版本),但让我扩展 @g00glen00b 关于如何编写单元测试的评论。

确保您的pom.xml 中有以下依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

正如评论中指出的那样,@RunWith(SpringJUnit4ClassRunner.class) 导致单元测试启动整个应用程序,它被用于集成测试。

幸运的是,Spring-boot 内置了对 Mockito 的依赖项,这正是您进行此类单元测试所需要的。

现在,您的单元测试可能如下所示:

public class EmployeeRepositoryTest 

@InjectMocks
private EmployeeRepository employeeRepository;

@Mock
private Something something; // some class that is used inside EmployRepository (if any) and needs to be injected

@Before
public void setUp() 
    MockitoAnnotations.initMocks(this);


@Test
public void insertEmploee()

    Employee employee = new Employee();

    employee.setEmpName("Azad");
    employee.setEmpDesignation("Engg");
    employee.setEmpSalary(12.5f);

    employeeRepository.save(employee);

    Mockito.verify(...); // verify what needs to be verified
    

可以找到关于使用 Mockito 的好帖子,例如,here。

【讨论】:

无法实例化名为“employeeRepository”的 InjectMocks 字段。您没有在字段声明时提供实例,所以我尝试构建实例。但是,我失败了,因为:'EmployeeRepository' 类型是一个接口。 InjectMocks 正确使用示例: InjectMocks Service service = new Service(); InjectMocks Service 服务; 我不知道这是一个 Spring JPA 存储库(尽管从名称上应该很明显)。在这种情况下,它实际上是一个集成测试,您最初的尝试是正确的。我的帖子主要适用于需要实例化的类。它可能会帮助您进行其他一些单元测试。 Spring 存储库不必进行单元测试(它们已经在 Spring 中)。您只能对它们执行集成测试。希望有意义 这可能是一个有用的阅读:***.com/questions/23435937/…【参考方案2】:

我们可以使用@MockBean 而不是在EmployeeRepository 上使用@Autowired,因为我们正在编写单元测试,我们不需要处理真实数据,我们只需要验证函数是否正常工作。检查下面的代码

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Main.class)//main springboot class
@WebAppConfiguration
public abstract class AbstractBaseTest 
   protected MockMvc mvc;
   @Autowired
   WebApplicationContext webApplicationContext;

   protected void setUp() 
      mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
   

    

public class EmployeeRepositoryTest extends AbstractBaseTest

@MockBean
protected EmployeeRepository employeeRepository;

 @Override
   @Before
   public void setUp() 
      super.setUp();
   

@Test
public void insertEmploee()

    Employee employee = new Employee();

    employee.setEmpName("Azad");
    employee.setEmpDesignation("Engg");
    employee.setEmpSalary(12.5f);

       Mockito.doNothing().when(employeeRepository).save(Mockito.any(Employee.class));
       employeeRepository.save(employee);
       Mockito.verify(employeeRepository, Mockito.times(1)).save(employee);



【讨论】:

以上是关于Spring Boot 单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 中的单元测试

spring boot单元测试spring context重复加载问题

Spring Boot使用单元测试

spring boot10.spring boot下的单元测试

Spring Boot APP - 单元测试[重复]

Spring Boot 单元测试,保姆级教程!