如何测试简单的 Spring Boot 应用程序

我们有一个示例 Spring 启动应用程序,它将用户数据存储在 MongoDB 中,我们使用 Rest 服务来检索数据

首先是域类,即 POJO

@Document
public class User{
    @Id
    private String id;

    private String name;

}

基于 Spring Data MongoDB 的相应存储库

public interface UserRepository extends MongoRepository<User, String> {
}

那我们的用户控制器

@RestController
class UserController {
 
    @Autowired
    private UserRepository repository;
 
    @RequestMapping("/users")
    List<User> users() {
        return repository.findAll();
    }
 
    @RequestMapping(value = "/Users/{id}", method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    void delete(@PathVariable("id") String id) {
        repository.delete(id);
    }
 
    // more controller methods
}

最后是我们的 Spring Boot 应用程序

@SpringBootApplication
public class Application {
    public static void main(String args[]){
     SpringApplication.run(Application.class, args);
    }
}

如果,让我们说 John Cena,The Rock 和 TripleHHH 是数据库中唯一的三个用户,对/ users 的请求会给出以下响应:

$ curl localhost:8080/users
[{"name":"John Cena","id":"1"},{"name":"The Rock","id":"2"},{"name":"TripleHHH","id":"3"}]

现在要测试代码,我们将验证应用程序是否正常工作

@RunWith(SpringJUnit4ClassRunner.class)   // 1
@SpringApplicationConfiguration(classes = Application.class)   // 2
@WebAppConfiguration   // 3
@IntegrationTest("server.port:0")   // 4
public class UserControllerTest {

    @Autowired   // 5
    UserRepository repository;

    User cena;
    User rock;
    User tripleHHH;

    @Value("${local.server.port}")   // 6
    int port;

    @Before
    public void setUp() {
        // 7
        cena = new User("John Cena");
        rock = new User("The Rock");
        tripleHHH = new User("TripleHH");

        // 8
        repository.deleteAll();
        repository.save(Arrays.asList(cena, rock, tripleHHH));

        // 9
        RestAssured.port = port;
    }

    // 10
    @Test
    public void testFetchCena() {
        String cenaId = cena.getId();

        when().
                get("/Users/{id}", cenaId).
        then().
                statusCode(HttpStatus.SC_OK).
                body("name", Matchers.is("John Cena")).
                body("id", Matchers.is(cenaId));
    }

    @Test
    public void testFetchAll() {
        when().
                get("/users").
        then().
                statusCode(HttpStatus.SC_OK).
                body("name", Matchers.hasItems("John Cena", "The Rock", "TripleHHH"));
    }

    @Test
    public void testDeletetripleHHH() {
        String tripleHHHId = tripleHHH.getId();

        when()
                .delete("/Users/{id}", tripleHHHId).
        then().
                statusCode(HttpStatus.SC_NO_CONTENT);
    }
}

说明

  1. 像任何其他基于 Spring 的测试一样,我们需要 SpringJUnit4ClassRunner 以便创建应用程序上下文。
  2. @SpringApplicationConfiguration 注释类似于 @ContextConfiguration 注释,因为它用于指定应在测试中使用的应用程序上下文。此外,它还将触发读取 Spring Boot 特定配置,属性等的逻辑。
  3. @WebAppConfiguration 必须存在才能告诉 Spring 应该加载 WebApplicationContext 进行测试。它还提供了一个属性,用于指定 Web 应用程序根目录的路径。
  4. @IntegrationTest 用于告诉 Spring Boot 应该启动嵌入式 Web 服务器。通过提供冒号或等号分隔的名称 - 值对,可以覆盖任何环境变量。在此示例中,server.port:0 将覆盖服务器的默认端口设置。通常,服务器将开始使用指定的端口号,但值 0 具有特殊含义。当指定为 0 时,它告诉 Spring Boot 扫描主机环境中的端口并在随机可用端口上启动服务器。如果我们在开发机器上占用不同端口的不同服务以及可能与应用程序端口发生冲突的构建服务器,那么这很有用,在这种情况下应用程序将无法启动。其次,如果我们使用不同的应用程序上下文创建多个集成测试,
  5. 我们可以访问应用程序上下文,并可以使用自动装配来注入任何 Spring bean。
  6. @Value("${local.server.port}”) 将被解析为使用的实际端口号。
  7. 我们创建了一些可用于验证的实体。
  8. 清除 MongoDB 数据库并为每个测试重新初始化,以便我们始终针对已知状态进行验证。由于未定义测试的顺序,因此如果 testFetchAll() 测试在 testDeletetripleHHH() 测试之后执行,则测试失败的可能性很小。
  9. 我们指示 Rest Assured 使用正确的端口。它是一个开源项目,提供用于测试 restful 服务的 Java DSL
  10. 测试通过使用 Rest Assured 实现。我们可以使用 TestRestTemplate 或任何其他 http 客户端来实现测试,但我使用 Rest Assured,因为我们可以使用 RestDocs 编写简明的文档