如何在Spring Boot中测试服务,端点和存储库

by Emre Savcı

由EmreSavcı

如何在Spring Boot中测试服务,端点和存储库 (How to test services, endpoints, and repositories in Spring Boot)

In this post I will show you how to write unit tests in spring boot applications.

在这篇文章中,我将向您展示如何在Spring Boot应用程序中编写单元测试。

Why is it necessary to write unit test requires another article to explain. But for a brief explanation, I will tell you several things.

为什么需要编写单元测试需要另一篇文章进行解释。 但为简要说明,我将告诉您几件事。

I usually defend the argument that code without unit tests is dead code. Because, when a developer adds a new feature to some code which is not covered by a unit test, it is prone to override existing business rules (which kills the code written before). Maybe it’s not exactly prone to it, but you can imagine what errors can occur when a complex project needs to be changed. Unit testing is the only way to protect your code against breaking changes.

我通常会辩称没有单元测试的代码就是无效代码。 因为,当开发人员向单元测试未涵盖的某些代码中添加新功能时,它倾向于覆盖现有的业务规则(这会杀死之前编写的代码)。 也许不是很容易,但是您可以想象当需要更改复杂的项目时会发生什么错误。 单元测试是保护代码免遭重大更改的唯一方法。

为什么要进行单元测试端点? (Why unit test endpoints?)

Every time we write an endpoint we need to be sure several things work correctly. The endpoint should return the data in the correct structure and handle the request correctly. We can test it manually, which is not preferable. So we write unit tests to ensure that our endpoints work correctly. There is also another way for testing endpoints known as automation tests, but that is not the subject of this post.

每次我们编写端点时,都需要确保几项工作正常。 端点应以正确的结构返回数据并正确处理请求。 我们可以手动测试它,这是不可取的。 因此,我们编写单元测试以确保端点正常工作。 还有另一种测试端点的方法称为自动化测试,但这不是本文的主题。

为什么要进行单元测试服务? (Why unit test services?)

It should be clear already, but just in case: we need to be sure our business logic works correctly.

应该已经很清楚了,但是以防万一:我们需要确保我们的业务逻辑正确运行。

为什么要进行单元测试存储库? (Why unit test repositories?)

There are several cases to test repositories. Of course we don’t test the framework itself. But we do write unit tests to be sure that our specifications or relations have been implemented correctly.

有几种情况可以测试存储库。 当然,我们不会测试框架本身。 但是我们会编写单元测试,以确保我们的规范或关系已正确实现。

那么我们如何测试控制器? (So how do we test controllers?)

Now it’s time to show you how to test our controllers in spring boot. Let’s imagine we write an application which allows us to save users in a database. We define a user entity, a user service, and a controller.

现在该向您展示如何在Spring Boot中测试我们的控制器。 假设我们编写了一个应用程序,该应用程序允许我们将用户保存在数据库中。 我们定义一个用户实体,一个用户服务和一个控制器。

Note: The examples shown in this post are not for real production use architecture

注意:本文中显示的示例不适用于实际的生产使用体系结构

@Data@Entitypublic class User {    @Id    @GeneratedValue(generator = "uuid2")    @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")    @Column(name = "id", columnDefinition = "BINARY(16)")    private UUID id;    private String name;    private String email;    private int age;}
@Datapublic class CreateUserRequest {    private String name;    private String email;    private int age;}
@RestController@RequestMapping("/users")public class UserController {    UserService userService;    @Autowired    public UserController(UserService userService) {        this.userService = userService;    }    @PostMapping    public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {        User created = userService.save(request);        return ResponseEntity.ok(created);    }}

Our controller has a dependency on UserService but we aren’t interested in what service does right now.

我们的控制器依赖于UserService,但是我们现在对什么服务不感兴趣。

So now let’s write a unit test for our controller to be sure it works correctly.

因此,现在让我们为控制器编写一个单元测试,以确保其正常工作。

We mocked our service because we don’t need its implementation details. We just test our controller here. We use MockMvc here to test our controller and object mapper for serialization purposes.

我们嘲笑我们的服务,因为我们不需要它的实现细节。 我们只是在这里测试我们的控制器。 我们在这里使用MockMvc来测试我们的控制器和对象映射器以进行序列化。

We setup our userService.Save() method to return the desired user object. We passed a request to our controller and after that we checked the returned data with the following line: andExpect(jsonPath("$.name").value(request.getName())) .

我们设置userService.Save()方法以返回所需的用户对象。 我们向控制器传递了一个请求,然后我们使用以下行检查了返回的数据: andExpect(jsonPath("$.name").value(request.getName()))

We have also other methods to use. Here is the list of methods:

我们还有其他方法可以使用 。 这是方法列表:

When we run the test we see that it passes.

当我们运行测试时,我们看到它通过了。

我们如何测试服务? (How do we test services?)

Now we go to test our UserService. It is quite simple to test.

现在我们去测试我们的UserService。 测试非常简单。

We mock the repository and inject our mocks into UserService. Now when we run the test we’ll see that it passes.

我们模拟存储库,并将模拟内容注入UserService。 现在,当我们运行测试时,我们将看到它通过了。

Now let’s add a business rule to UserService: let’s say the user must have an email address.

现在,向UserService添加业务规则:假设用户必须具有电子邮件地址。

We change our save method in UserService as below:

我们在UserService中更改保存方法,如下所示:

public User save(CreateUserRequest request) {    requireNonNull(request.getEmail());        User user = new User();    user.setName(request.getName());    user.setEmail(request.getEmail());    user.setAge(request.getAge());    userRepository.save(user);    return user;}

When we run the test again, we’ll see a failed test.

当我们再次运行测试时,我们将看到失败的测试。

Before we fix it, let’s write a test that satisfies this business.

在修复它之前,让我们编写一个满足该业务的测试。

We wrote a new test that specified that if we send a null email, it’ll throw NullPointerException.

我们编写了一个新的测试,指定如果我们发送空电子邮件,它将抛出NullPointerException.

Let’s fix the failed test by adding an email to our request:

让我们通过向请求添加电子邮件来修复失败的测试:

createUserRequest.setEmail("testemail");

Run both tests:

运行两个测试:

我们如何测试存储库? (How do we test repositories?)

Now we’ve come to testing repositories. We use an in memory h2 database with TestEntityManager.

现在我们来测试存储库。 我们使用带有TestEntityManager.内存h2数据库TestEntityManager.

Our repository is defined as below:

我们的存储库定义如下:

@Repositorypublic interface UserRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {    Optional<User> findById(UUID id);}

First configure h2db. Create the file name application.yaml in test -> resources path:

首先配置h2db。 在测试->资源路径中创建文件名application.yaml:

spring:  application:    name: Spring Boot Rest API  datasource:    type: com.zaxxer.hikari.HikariDataSource    url: "jdbc:h2:mem:test-api;INIT=CREATE SCHEMA IF NOT EXISTS dbo\\;CREATE SCHEMA IF NOT EXISTS definitions;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;MODE=MSSQLServer"    name:    password:    username:    initialization-mode: never    hikari:      schema: dbo  jpa:    database: H2    database-platform: org.hibernate.dialect.H2Dialect    show-sql: true    hibernate:      ddl-auto: create-drop  test:    database:      replace: none

And let’s first write a basic test for our repository: save a user and retrieve it:

让我们首先为存储库编写一个基本测试:保存用户并检索它:

@RunWith(SpringRunner.class)@DataJpaTestpublic class UserRepositoryTest {    @Autowired    TestEntityManager entityManager;    @Autowired    UserRepository sut;    @Test    public void it_should_save_user() {        User user = new User();        user.setName("test user");        user = entityManager.persistAndFlush(user);        assertThat(sut.findById(user.getId()).get()).isEqualTo(user);    }}

When we run it we’ll see bunch of console output, and also our test passes:

运行它时,我们将看到一堆控制台输出,并且我们的测试通过了:

Now let’s add another method to our repository for searching for a user via email:

现在,让我们向存储库中添加另一种方法,以通过电子邮件搜索用户:

Optional<User> findByEmail(String email);

And write another test:

并编写另一个测试:

@Testpublic void it_should_find_user_byEmail() {    User user = new User();    user.setEmail("testmail@test.com");    user = entityManager.persistAndFlush(user);    assertThat(sut.findByEmail(user.getEmail()).get()).isEqualTo(user);}

When we take a look at the console after running the test, we'll see the SQL generated by hibernate:

运行测试后查看控制台时,我们将看到由hibernate生成SQL:

SELECT user0_.id AS id1_1_,user0_.age AS age2_1_,user0_.email AS email3_1_,user0_.name AS name4_1_FROM user user0_WHERE user0_.email=?

So far so good. We have covered the basics of unit testing with spring boot.

到目前为止,一切都很好。 我们已经介绍了使用Spring Boot进行单元测试的基础知识。

Now you don’t have any excuses to not write unit tests! I hope it is clear to you to how to write unit tests for different kinds of purposes.

现在,您没有任何借口不编写单元测试! 我希望您很清楚如何为各种目的编写单元测试。

翻译自: https://www.freecodecamp.org/news/unit-testing-services-endpoints-and-repositories-in-spring-boot-4b7d9dc2b772/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值