在Spring Boot中使用Docker在测试中进行高级功能测试(一)

想更多地了解Spring Boot项目中的功能测试吗?这篇分享至优锐课的学习笔记带你了解有关在测试中使用Docker容器的更多信息。

本文重点介绍在Spring Boot应用程序的功能测试期间应用一些最佳实践。我们将演示一种高级方法,该方法如何在不设置登台环境的情况下将服务作为黑盒进行测试。深入探讨可以进Java学习资料交流qq群:907135806 一起讨论。

理论

让我们从定义功能测试的含义开始:

功能测试是在软件开发中使用的软件测试过程,其中对软件进行测试以确保其符合所有要求。功能测试是一种检查软件的方法,以确保软件具有其功能要求中指定的所有必需功能。

尽管这有点令人困惑,但请不要担心——以下定义提供了进一步的解释:

功能测试主要用于验证某个软件所提供的输出与最终用户或企业所需的输出相同。通常,功能测试涉及评估每个软件功能并将其与业务需求进行比较。通过为软件提供一些相关的输入来对其进行测试,以便可以评估输出以查看其与基本要求相比是否相符,相关或变化。此外,功能测试还检查软件的可用性,例如通过确保导航功能按要求工作。

在我们的案例中,我们将微服务作为软件,应根据最终用户的要求提供一些输出。

目的

功能测试应涵盖我们应用程序的以下方面:
• 上下文启动-确保服务在上下文中没有冲突,并且可以顺利引导。
• 业务需求/用户案例-这包括请求的功能。

基本上,每个(或大多数)用户故事都应该有自己专用的功能测试。如果至少有一个功能测试,我们不需要编写上下文启动测试,因为它仍然会测试它。

实践

为了演示如何应用最佳实践,我们需要编写一些示例服务。让我们从头开始。

任务

我们的新服务要求满足以下要求:
• 用于存储和检索用户详细信息的REST API。
• REST API,用于通过REST从联系人服务获取丰富的联系方式的用户详细信息。

架构设计

对于此任务,我们将使用Spring平台作为框架,并使用Spring Boot作为应用程序引导程序。为了存储用户详细信息,我们将使用MariaDB。
由于该服务应存储和检索用户详细信息,因此将其命名为“用户详细信息”服务是合乎逻辑的。
在实施之前,应制作组件图以更好地了解系统的主要组件:在Spring Boot中使用Docker在测试中进行高级功能测试(一)_第1张图片

实操

以下示例代码包含许多Lombok批注。你可以在网站上的docs文件中找到有关每个注释的说明。

Models

用户详细信息模型:

@Value(staticConstructor = "of")
public class UserDetails {
    String firstName;
    String lastName;
    public static UserDetails fromEntity(UserDetailsEntity entity) {
        return UserDetails.of(entity.getFirstName(), entity.getLastName());
    }
    public UserDetailsEntity toEntity(long userId) {
        return new UserDetailsEntity(userId, firstName, lastName);
    }
}

用户联系人模型:

@Value
public class UserContacts {
    String email;
    String phone;
}

具有汇总信息的用户:

@Value(staticConstructor = "of")
public class User {
    UserDetails userDetails;
    UserContacts userContacts;
}

REST API

@RestController
@RequestMapping("user")
@AllArgsConstructor
public class UserController {
    private final UserService userService;
    @GetMapping("/{userId}") //1
    public User getUser(@PathVariable("userId") long userId) {
        return userService.getUser(userId);
    }
    @PostMapping("/{userId}/details") //2
    public void saveUserDetails(@PathVariable("userId") long userId, @RequestBody UserDetails userDetails) {
        userService.saveDetails(userId, userDetails);
    }
    @GetMapping("/{userId}/details") //3
    public UserDetails getUserDetails(@PathVariable("userId") long userId) {
        return userService.getDetails(userId);
    }
}
  1. 按ID获取用户汇总数据
  2. 按ID为用户发布用户详细信息
  3. 通过ID获取用户详细信息

联系人服务客户端

@Component
public class ContactsServiceClient {
    private final RestTemplate restTemplate;
    private final String contactsServiceUrl;
    public ContactsServiceClient(final RestTemplateBuilder restTemplateBuilder,
                                 @Value("${contacts.service.url}") final String contactsServiceUrl) {
        this.restTemplate = restTemplateBuilder.build();
        this.contactsServiceUrl = contactsServiceUrl;
    }
    public UserContacts getUserContacts(long userId) {
        URI uri = UriComponentsBuilder.fromHttpUrl(contactsServiceUrl + "/contacts")
                .queryParam("userId", userId).build().toUri();
        return restTemplate.getForObject(uri, UserContacts.class);
    }
}

详细信息实体及其存储库

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDetailsEntity {
    @Id
    private Long id;
    @Column
    private String firstName;
    @Column
    private String lastName;
}
@Repository
public interface UserDetailsRepository extends JpaRepository<UserDetailsEntity, Long> {
}

用户服务

@Service
@AllArgsConstructor
public class UserService {
    private final UserDetailsRepository userDetailsRepository;
    private final ContactsServiceClient contactsServiceClient;
    public User getUser(long userId) {
        UserDetailsEntity userDetailsEntity = userDetailsRepository.getOne(userId); //1
        UserDetails userDetails = UserDetails.fromEntity(userDetailsEntity);
        UserContacts userContacts = contactsServiceClient.getUserContacts(userId); //2
        return User.of(userDetails, userContacts); //3
    }
    public void saveDetails(long userId, UserDetails userDetails) {
        UserDetailsEntity entity = userDetails.toEntity(userId);
        userDetailsRepository.save(entity);
    }
    public UserDetails getDetails(long userId) {
        UserDetailsEntity userDetailsEntity = userDetailsRepository.getOne(userId);
        return UserDetails.fromEntity(userDetailsEntity);
    }
}
  1. 从数据库检索用户详细信息
  2. 从通讯录服务中检索用户通讯录
  3. 向用户返回汇总数据

应用及其属性

UserDetailsServiceApplication.java

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

application.properties:

#contact service
contacts.service.url=http://www.prod.contact.service.com
#database
user.details.db.host=prod.maria.url.com
user.details.db.port=3306
user.details.db.schema=user_details
spring.datasource.url=jdbc:mariadb://${user.details.db.host}:${user.details.db.port}/${user.details.db.schema}
spring.datasource.username=prod-username
spring.datasource.password=prod-password
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver

POM文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>user-details-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>User details service</name>
    <parent>
        <groupId>com.tdanylchuk</groupId>
        <artifactId>functional-tests-best-practices</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

注意:父级是自定义的功能测试最佳实践项目,该项目继承了spring-boot-starter-parent。稍后将介绍其目的。
Structure

这几乎是我们满足初始需求所需的一切:保存和检索用户详细信息以及检索包含联系人的用户详细信息。

下篇接着来:
在Spring Boot中使用Docker在测试中进行高级功能测试(二)
————————————————————
想要更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java学习资料和视频课程可以留言或者加微信:ddmsiqi 直接获取~感谢阅读!

你可能感兴趣的:(Java,编程)