【问题标题】:MockMvc returned HttpMessageNotWritableException with application/jsonMockMvc 使用 application/json 返回 HttpMessageNotWritableException
【发布时间】:2021-02-07 13:00:52
【问题描述】:

我有一个带有 spring 2.3.4.RELEASE 的休息端点 当我使用 MockMvc 对控制器运行测试时,我收到了

w.s.m.s.DefaultHandlerExceptionResolver:已解决 [org.springframework.http.converter.HttpMessageNotWritableException: 没有预设的 [class com.example.myexample.model.User] 转换器 内容类型'application/json']

@SpringBootTest(classes = UserController.class)
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserRepository userRepository;

    private static final String GET_USERBYID_URL = "/users/{userId}";
    

    @Test
    public void shouldGetUserWhenValid() throws Exception {
        Address address = new Address();
        address.setStreet("1 Abc St.");
        address.setCity("Paris");

        User userMock = new User();
        userMock.setFirstname("Lary");
        userMock.setLastname("Pat");
        userMock.setAddress(address);

        when(userRepository.findById(1)).thenReturn(Optional.of(userMock));

        mockMvc.perform(get(GET_USERBYID_URL, "1").accept(MediaType.APPLICATION_JSON))
               .andDo(print())
               .andExpect(status().isOk());
    }
}


@RestController
@RequestMapping(path = "/users")
@Slf4j
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping(value = "/{userId}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<User> getUser(@PathVariable("userId") Integer userId) {
        log.info("Getting user with id={}", userId);
        final Optional<User> userOptional = userRepository.findById(userId)

        return userOptional.map(value -> ResponseEntity.ok()
                                               .contentType(MediaType.APPLICATION_JSON)
                                               .body(value))
                   .orElseGet(() -> ResponseEntity.noContent()
                                                  .build()).ok()
                           .body(userOptional.get());

    }
}


@Data
public class User {
    private String firstname;
    private String lastname;
    private Address address;
}

@Data
public class Address {
    private String street;
    private String city;
}

@Repository
public interface UserRepository extends CrudRepository<User, Integer> {
}

我读过其他文章建议添加杰克逊依赖,但这对我不起作用。

<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.11.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.11.3</version>
        </dependency>

这是我的 pom.xml

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

<groupId>org.example</groupId>
<artifactId>myexample</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
    <lombok.version>1.18.12</lombok.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>RELEASE</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.11.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.11.3</version>
    </dependency>



    <!-- test dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

如果我运行应用程序并通过邮递员对其进行测试,则端点工作正常。 任何想法为什么我在我的休息控制器测试中收到此错误消息?

【问题讨论】:

  • 请输入用户控制器类。
  • @tashkhisi 用户控制器代码在那里。我有 UserController、UserRepository 和所有模型。

标签: java spring spring-boot java-8 spring-test


【解决方案1】:

问题在于你的@SpringBootTest,当你添加classes = UserController.class时,它告诉spring用UserController.class创建一个上下文。所以它只使用 UserController 创建弹簧上下文。因此,只创建了您的控制器 bean,而没有创建 Http 消息转换所需的其他 bean。所以一种解决方案是从@SpringBootTest 中删除classes = UserController.class

@SpringBootTest
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc

现在运行测试应该没有问题了。
但这带来了另一个问题,现在这将加载完整的 spring 上下文,这对于控制器层测试来说是不需要的。它还会增加单元测试的时间。
为了解决这个问题,spring 有另一个注解@WebMvcTest。如果您使用 @WebMvcTest 注释您的测试,Spring Boot 只会实例化 Web 层而不是整个上下文。您也可以选择仅实例化一个控制器。例如,

@ExtendWith(SpringExtension.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {

}

这应该可以解决您的问题。

【讨论】:

  • 感谢您的回答。我试过了,它并没有解决问题。
【解决方案2】:

显然我把 UserControllerTest 放在了错误的包名中。 在我将 UserControllerTest 放在与 UserController 相同的包名中后,它现在可以工作了。

【讨论】:

  • 谢谢,谢谢,我花了一些时间试图解决这个问题
猜你喜欢
  • 1970-01-01
  • 2014-10-29
  • 2019-09-17
  • 2021-08-31
  • 2014-02-28
  • 2020-01-18
  • 2013-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多