单元测试实战(一)Controller 的测试

为鼓励单元测试,特分门别类示例各种组件的测试代码并进行解说,供开发人员参考。

本文中的测试均基于JUnit5。

单元测试实战(一)Controller 的测试

单元测试实战(二)Service 的测试   

单元测试实战(三)JPA 的测试    

单元测试实战(四)MyBatis-Plus 的测试

单元测试实战(五)普通类的测试

单元测试实战(六)其它

概述

Controller的测试,要点在于模拟一个HTTP请求过来,相应的handler方法能正确处理之。

测试应遵循经典三段式:given、when、then;即:假设xxx……那么当yyy时……应该会zzz。

测试类推荐使用@WebMvcTest注解,并传入要测试的Controller类作为参数。

在每个测试之前应清理/重置测试数据,即模拟前端发过来的请求参数或请求体。

断言应主要检查响应对象(包括返回码)。

依赖

测试使用JUnit以及Spring Boot自带的测试工具集,如Mockito、Hamcrest、Assertj等,后续章节也一样。依赖如下:

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

示例1

以下是一个控制器,UserController,主要完成对User实体的CRUD功能:

package com.aaa.api.auth.controller;import com.aaa.api.auth.entity.User;
import com.aaa.api.auth.service.UserService;
import com.aaa.sdk.rest.global.EnableGlobalResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/users")
@EnableGlobalResult
public class UserController {private final Logger log = LoggerFactory.getLogger(UserController.class);private final UserService service;public UserController(UserService service) {this.service = service;}@GetMapping("/{id}")public User getUser(@PathVariable("id") Long id) {return service.findById(id);}@GetMapping("/q")public User findUser(@RequestParam("userCode") String userCode) {return service.findByUserCode(userCode);}@GetMappingpublic List<User> getAll() {return service.findAll();}@PostMappingpublic User save(@RequestBody User user) {return service.save(user);}
}

以下是对UserController进行测试的测试类:

package com.aaa.api.auth.controller;import com.aaa.api.auth.entity.User;
import com.aaa.api.auth.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;import java.util.List;import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;@WebMvcTest(UserController.class)
class UserControllerTest {@Autowiredprivate MockMvc mockMvc;@MockBeanprivate UserService svc;@Autowiredprivate ObjectMapper objectMapper;private final User u1 = new User();private final User u2 = new User();private final User u3 = new User();@BeforeEachvoid setUp() {u1.setName("张三");u1.setUserCode("zhangsan");u1.setRole(User.ADMIN);u1.setEmail("zhangsan@aaa.net.cn");u1.setMobile("13600001234");u2.setName("李四");u2.setUserCode("lisi");u2.setRole(User.ADMIN);u2.setEmail("lisi@aaa.net.cn");u2.setMobile("13800001234");u3.setName("王五");u3.setUserCode("wangwu");u3.setRole(User.USER);u3.setEmail("wangwu@aaa.net.cn");u3.setMobile("13900001234");}@Testvoid testGetUser() throws Exception {// given - precondition or setuplong id = 1L;given(svc.findById(id)).willReturn(u1);// when -  action or the behaviour that we are going testResultActions response = mockMvc.perform(get("/users/{id}", id));// then - verify the outputresponse.andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.userCode", is(u1.getUserCode()))).andExpect(jsonPath("$.name", is(u1.getName()))).andExpect(jsonPath("$.email", is(u1.getEmail())));}@Testvoid testFindUser() throws Exception {// given - precondition or setupgiven(svc.findByUserCode(any())).willReturn(u1);// when -  action or the behaviour that we are going testResultActions response = mockMvc.perform(get("/users/q?userCode=zhangsan"));// then - verify the outputresponse.andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.userCode", is(u1.getUserCode())));}@Testvoid testGetAll() throws Exception {// given - precondition or setupList<User> listOfUsers = List.of(u1, u2, u3);given(svc.findAll()).willReturn(listOfUsers);// when -  action or the behaviour that we are going testResultActions response = mockMvc.perform(get("/users"));// then - verify the outputresponse.andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.size()", is(listOfUsers.size())));}@Testvoid testSave() throws Exception {// given - precondition or setupgiven(svc.save(any())).willAnswer((invocation)-> invocation.getArgument(0));// when - action or behaviour that we are going testResultActions response = mockMvc.perform(post("/users").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(u1)));// then - verify the result or output using assert statementsresponse.andDo(print()).andExpect(status().isOk()) // it's NOT 'created', as our controller is returning 200..andExpect(jsonPath("$.userCode", is(u1.getUserCode()))).andExpect(jsonPath("$.name", is(u1.getName()))).andExpect(jsonPath("$.role", equalTo(u1.getRole().intValue())));}
}

测试类说明:

第28行我们声明这是个WebMvcTest,并且是对UserController类进行测试。

第32行我们声明了一个MockMvc对象,并标注为@AutoWired,这是Spring提供的MVC测试组件,通常每个Controller测试类都需要。

第35行我们声明了一个@MockBean,是个Service。因为UserController会注入一个UserService对象,所以这里我们Mock了一个(@MockBean注解会将Mock出的对象加入测试application context)。

第38行的ObjectMapper则是我们测试中用来进行对象-JSON转换的工具,使用@AutoWired是因为测试框架本身就提供这种Bean。

第40-42行提供了三个测试数据,并在setUp()方法中进行初始化/重置。@BeforeEach注解使得setUp()方法在每个测试之前都会执行一遍。

接下来,从65行开始,是测试方法;每个方法都遵循given - when - then三段式。

testGetUser方法是测试根据id获取User对象的。它假设service组件的findById(1)会返回对象u1;那么当访问"/users/1"这个路径时(即调用UserController的getUser方法时);返回的响应体就应该是转成JSON串的u1对象。注意我们使用jsonPath来取返回对象的属性,'$'代表根对象。

testFindUser方法是测试根据用户编码查询User对象的。它假设service组件的findByUserCode()无论传什么参数都会返回对象u1;那么当访问"/users/q?userCode=zhangsan"这个路径时(即调用UserController的findUser方法时);返回的响应体就应该是转成JSON串的u1对象。

testGetAll方法是测试获取所有User对象的。它假设service组件的findAll()会返回对象u1、u2、u3;那么当访问"/users"这个路径时(即调用UserController的getAll方法时);返回的响应体就应该是转成JSON串的u1、u2、u3对象集合。

testSave方法是测试保存User对象的。它假设service组件在save()任何User对象时都会返回该对象本身;那么当对"/users"这个路径进行POST时(即调用UserController的save方法时);返回的响应体就应该是转成JSON串该User对象。

示例2

以下是集成SSO的Controller(即实现code换token功能的redirect_uri端点,以及logout端点),SSOIntegrationController:

package com.aaa.api.auth.controller;import com.aaa.sdk.auth.sso.OAuth2Token;
import com.aaa.sdk.auth.sso.OAuth2TokenHelper;
import com.aaa.sdk.rbac.RbacCacheNames;
import com.aaa.sdk.rest.global.GlobalResult;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;
import java.util.Map;/*** 与集团SSO的集成。提供code换token(即所谓的redirect_uri)端点、logout端点。*/
@RestController
@RequestMapping("/oauth")
public class SSOIntegrationController {private final Logger log = LoggerFactory.getLogger(SSOIntegrationController.class);private final OAuth2TokenHelper oAuth2TokenHelper;private final CacheManager cacheManager;public SSOIntegrationController(OAuth2TokenHelper oAuth2TokenHelper, CacheManager cacheManager) {this.oAuth2TokenHelper = oAuth2TokenHelper;this.cacheManager = cacheManager;}/*** 此为用授权码换token的端点,即redirect_uri。* @param code 授权码* @param state 获取token之后,经过Base64编码的重定向url。* @param request http请求* @param response http响应* @return 一个包含"username"和"access_token"两个键值对的Map。*/@GetMapping({"/token", "callback"})public GlobalResult<Map<String, String>> getTokenByCode(@RequestParam(name = "code", required = false) String code,@RequestParam(name = "state", required = false) String state,HttpServletRequest request,HttpServletResponse response) throws IOException {// 如果没有指定redirectUri,则使用当前的URIString fallbackRedirectUri = getFullURL(request);if (!StringUtils.hasText(code)) {// 如果授权码为空,则先请求授权码String authorizeCodeUri = oAuth2TokenHelper.buildAuthorizeCodeUri(state, fallbackRedirectUri);response.sendRedirect(authorizeCodeUri);return null;}// 使用授权码换取tokenOAuth2Token oAuth2Token = oAuth2TokenHelper.getAccessToken(code, fallbackRedirectUri);if (oAuth2Token == null) {log.error("Failed in exchanging token with code!");return GlobalResult.fail(101001, "获取token失败");}// 清除登录用户权限的缓存RbacCacheNames.evictUserCache(cacheManager, oAuth2Token.getUsername());// 重定向当前url到指定redirectUriString loginRedirectUri = oAuth2TokenHelper.getLoginRedirectUri(state, oAuth2Token.getAccessToken());log.debug("Will redirect user to {}", loginRedirectUri);response.sendRedirect(loginRedirectUri);log.info("User {}/{} login", oAuth2Token.getUserId(), oAuth2Token.getUsername());return GlobalResult.succeed(Map.of("username",     oAuth2Token.getUsername(),"access_token", oAuth2Token.getAccessToken()));}/*** 用户登出。* @param state 获取token之后,经过Base64编码的重定向url* @param request http请求* @param response http响应*/@GetMapping("/logout")public void logout(@RequestParam(name = "state", required = false) String state,HttpServletRequest request,HttpServletResponse response) throws IOException {String fallbackRedirectUri = getFullURL(request).replaceAll("/logout", "/token");String logoutUri = oAuth2TokenHelper.buildLogoutUri(state, fallbackRedirectUri);response.sendRedirect(logoutUri);}private String getFullURL(HttpServletRequest request) {StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString());String queryString = request.getQueryString();if (queryString == null) {return requestURL.toString();} else {return requestURL.append('?').append(queryString).toString();}}}

以下是对SSOIntegrationController进行测试的测试类:

package com.aaa.api.auth.controller;import com.aaa.sdk.auth.sso.OAuth2Token;
import com.aaa.sdk.auth.sso.OAuth2TokenHelper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@WebMvcTest(SSOIntegrationController.class)
class SSOIntegrationControllerTest {@Autowiredprivate MockMvc mockMvc;@MockBeanprivate OAuth2TokenHelper tokenHelper;private final OAuth2Token oauth2Token = new OAuth2Token();{oauth2Token.setAccessToken("123");oauth2Token.setRefreshToken("456");oauth2Token.setJti("abc");oauth2Token.setTokenType("jwt");oauth2Token.setExpiresIn(3600 * 1000);oauth2Token.setUserId("zhangsan");oauth2Token.setUsername("zhangsan");}@Testvoid testGetTokenByCode() throws Exception {// given - precondition or setupgiven(tokenHelper.getAccessToken(any(), any())).willReturn(oauth2Token);given(tokenHelper.getLoginRedirectUri(any(), any())).willReturn("https://foo/bar");// when - action or behaviour that we are going testResultActions response = mockMvc.perform(get("/oauth/token?code=mycode&state=mystate"));// then - verify the result or output using assert statementsresponse.andDo(print()).andExpect(status().isFound()).andExpect(header().string("Location", "https://foo/bar")).andExpect(jsonPath("$.code", is(0))).andExpect(jsonPath("$.success", is(true))).andExpect(jsonPath("$.data.username", is("zhangsan"))).andExpect(jsonPath("$.data.access_token", is("123")));}@Testvoid testGetTokenByCode_EmptyCode() throws Exception {// given - precondition or setupsgiven(tokenHelper.buildAuthorizeCodeUri(any(), any())).willReturn("https://foo/oauth/token");// when - action or behaviour that we are going testResultActions response = mockMvc.perform(get("/oauth/token?state=mystate"));// then - verify the result or output using assert statementsMvcResult result = response.andDo(print()).andExpect(status().isFound()).andReturn();String content = result.getResponse().getContentAsString();assertThat(content.length()).isEqualTo(0);}@Testvoid testGetTokenByCode_NullAccessToken() throws Exception {// given - precondition or setupsgiven(tokenHelper.getAccessToken(any(), any())).willReturn(null);// when - action or behaviour that we are going testResultActions response = mockMvc.perform(get("/oauth/token?code=mycode&state=mystate"));// then - verify the result or output using assert statementsresponse.andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.success", is(false))).andExpect(jsonPath("$.code", not(0)));}@Testvoid testLogout() throws Exception {// given - precondition or setupsgiven(tokenHelper.buildLogoutUri(any(), any())).willReturn("https://foo/bar/login");// when - action or behaviour that we are going testResultActions response = mockMvc.perform(get("/oauth/logout?state=mystate"));// then - verify the result or output using assert statementsresponse.andDo(print()).andExpect(status().isFound()).andExpect(header().string("Location", "https://foo/bar/login"));}
}

测试类说明:

第23行,我们声明这是个WebMvcTest,并且是对SSOIntegrationController类进行测试。

第27行,我们同样需要一个MockMvc组件,不再赘述。

第30行,我们有一个类型为OAuth2TokenHelper的MockBean,这是因为SSOIntegrationController里有这个组件,我们需要mock其行为。

第32行,我们定义了一个OAuth2Token类型的测试数据oauth2Token,并且在34行的初始化块中初始化其各个属性。这是个测试中会用到的JWT令牌对象。

接下来,从第44行开始,是测试方法;每个方法都遵循given - when - then三段式。

testGetTokenByCode方法是测试code换token。它假设tokenHelper.getAccessToken会返回我们的测试数据oauth2Token,且tokenHelper.getLoginRedirectUri会返回"https://foo/bar";那么当访问"/oauth/token?code=mycode&state=mystate"这个路径时(即调用SSOIntegrationController的getTokenByCode方法时);返回的响应体就应该是转成JSON串的oauth2Token对象,且响应会指示浏览器重定向到"https://foo/bar"。该测试覆盖了getTokenByCode方法的正常分支。

testGetTokenByCode_EmptyCode方法同样是测试code换token。它假设tokenHelper.buildAuthorizeCodeUri会返回"https://foo/oauth/token";那么当访问"/oauth/token?state=mystate"这个路径时(即调用SSOIntegrationController的getTokenByCode方法但code为空时);返回的响应体是空。该测试覆盖了SSOIntegrationController第55行的if分支。注意在这个方法里我们取了response内容来进行assert,没有用jsonPath。

testGetTokenByCode_NullAccessToken方法仍旧测试code换token。它假设tokenHelper.getAccessToken会返回null;那么当访问"/oauth/token?code=mycode&state=mystate"这个路径时(即调用SSOIntegrationController的getTokenByCode方法时);返回的响应体是一个不成功的GlobalResult。该测试覆盖了SSOIntegrationController第63行的if分支。

testLogout方法是测试登出功能。它假设tokenHelper.buildLogoutUri返回"https://foo/bar/login";那么当访问"/oauth/logout?state=mystate"这个路径时(即调用SSOIntegrationController的logout方法时);返回的响应体会指示浏览器重定向到"https://foo/bar/login"。

总结

对于一个@WebMvcTest,我们一般都注入一个MockMvc组件。

对于待测类依赖的组件(典型的如Service),我们通常使用@MockBean来模拟出一个。如果不是组件(不是Spring Bean),我们可以直接用@Mock模拟。对于方便new出来的,也可以直接new出来(比如我们的三个user实体和oauth2Token对象)。Mockito还有一个@Spy注解,可以监控被注解的对象(该对象通常new出来,但Spy也可以像Mock那样对其行为进行打桩)。总之,@Mock、@Spy、@MockBean、@SpyBean、@Autowired以及new出来的对象,都是为了模拟、订制该Controller所依赖的各种对象及其行为,方便我们测试。这种模拟,或曰打桩,是为了让我们能专注于待测试类的行为,而不致被其依赖的东西转移了注意力。假如我们都用真实的依赖,比如UserService,那么UserService自身的bug会导致我们的UserControllerTest失败,进一步而言,UserService又依赖于UserRepositoy,如果这个UserRepository有bug,那它又会同时导致UserServiceTest和UserControllerTest都失败——这就不是单元测试而是集成测试了;单元测试通常只关注单一类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/147839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ForkLift:macOS文件管理器/FTP客户端

ForkLift 是一款macOS下双窗口的文件管理器&#xff0c;可以代替本地的访达。ForkLift同时具备连接Ftp、SFtp、WebDav以及云服务器。 ForkLift还具备访达不具备的小功能&#xff0c;比如从文件夹位置打开终端&#xff0c;显示隐藏文件&#xff0c;制作替换等功能。ForkLift 是一…

Spring Cloud学习(九)【Elasticsearch 分布式搜索引擎01】

文章目录 初识 elasticsearch了解 ES倒排索引ES 的一些概念安装es、kibana安装elasticsearch部署kibana 分词器安装IK分词器ik分词器-拓展词库 索引库操作mapping 映射属性索引库的 CRUD 文档操作添加文档查看、删除文档修改文档Dynamic Mapping RestClient 操作索引库什么是Re…

代码随想录二刷 | 数组 | 移除元素

代码随想录二刷 &#xff5c; 数组 &#xff5c; 移除元素 题目描述解题思路 & 代码实现暴力解法双指针法 题目描述 27. 移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用…

【数据结构】F:B DS图_课程表 拓扑排序实现

F : B DS图_课程表 Description 小明这个学期必须选修n门课程&#xff0c;课程编号记为0到n-1。 在选修某些课程之前需要一些先修课程。先修课程按数组prerequisites给出&#xff0c;其中prerequisites[i] [a, b]&#xff0c;表示如果要学习课程a则必须先学习课程b。 例如&a…

Ubuntu/Debian Hat 系 Linux 使用

目录 1. Ubuntu/Debian Hat 系 Linux 使用1.1. 包1.1.1. Install Package1.1.2. Convert .rpm package to .deb1.1.3. Install RPM Package Directly Onto the System on Ubuntu1.1.4. Command not found 1. Ubuntu/Debian Hat 系 Linux 使用 1.1. 包 1.1.1. Install Package…

手搓哈希表、列表、队列,只为了用C语言快速求解华容道游戏,我不是大佬,只是一个游戏算法爱好者

背景 多年前曾经写过C语言求解华容道&#xff0c;当时没有用到哈希表&#xff0c;导致整个查重搜索数组过大&#xff0c;每次求解都得花上数分钟的时间&#xff0c;如今时过境迁&#xff0c;对数据结构和算法有了更深的理解&#xff0c;所以得把这一块补上了。(其实就是最近想…

Redis面经

Redis使用场景 1、缓存&#xff1a; 缓存三兄弟(穿透、击穿、雪崩) 、双写一致、持久化、数据过期策略&#xff0c;数据淘汰策略 2、分布式锁 setnx、redisson 3、消息队列 4、延迟队列 何种数据类型&#xff08;list、zset&#xff09; 缓存三兄弟 缓存穿透 缓存穿透…

Python 如何实现职责链设计模式?什么是职责链设计模式?Python 职责链设计模式示例代码

什么是职责链&#xff08;Chain of Responsibility&#xff09;设计模式&#xff1f; 职责链&#xff08;Chain of Responsibility&#xff09;设计模式是一种行为型设计模式&#xff0c;旨在构建一个对象链&#xff0c;每个对象都有机会处理请求&#xff0c;并且可以将请求传…

动手学深度学习——循环神经网络的从零开始实现(原理解释+代码详解)

文章目录 循环神经网络的从零开始实现1. 独热编码2. 初始化模型参数3. 循环神经网络模型4. 预测5. 梯度裁剪6. 训练 循环神经网络的从零开始实现 从头开始基于循环神经网络实现字符级语言模型。 # 读取数据集 %matplotlib inline import math import torchfrom torch import …

五、hdfs常见权限问题

1、常见问题 2、案例 &#xff08;1&#xff09;问题 &#xff08;2&#xff09;hdfs的超级管理员 &#xff08;3&#xff09;原因 没有使用Hadoop用户对hdfs文件系统进行操作。 在Hadoop文件系统中&#xff0c;Hadoop用户相当于Linux系统中的root用户&#xff0c;是最高级别用…

react实现步进器

创建一个步进器组件&#xff0c;包含当前步骤&#xff08;currentStep&#xff09;的状态以及前进和后退的操作&#xff1a; import React, { useState } from react;function Stepper() {const [currentStep, setCurrentStep] useState(1);const handleNext () > {setCu…

⑩② 【MySQL索引】详解MySQL`索引`:结构、分类、性能分析、设计及使用规则。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL索引 ⑩② 【MySQL索引】1. 索引2. 索引的…

搞科研、写论文,如何正确使用GPT?AIGC技术解析、提示词工程高级技巧、AI绘图、ChatGPT/GPT4应用

目录 专题一 OpenAI开发者大会最新技术发展及最新功能应用 专题二 AIGC技术解析 专题三 提示词工程高级技巧 专题四 ChatGPT/GPT4的实用案例 专题五 让ChatGPT/GPT4成为你的论文助手 专题六 让ChatGPT/GPT4成为你的编程助手 专题七 让ChatGPT/GPT4进行数据处理 专题八 …

Wordpress页面生成器:Elementor 插件制作网站页面教程(图文完整)

本文来教大家怎么使用Wordpress Elementor页面编辑器插件来自由创建我们的网页内容。很多同学在面对建站的时候,一开始都是热血沸腾信心满满的,等到实际上手的时候就会发现有很多问题都是无法解决的,希望本篇Elementor插件使用指南能够帮助到你。 Wordpress Elementor页面编…

解决React遍历每次渲染多个根元素导致无法为元素赋值key的问题

遍历时&#xff0c;存在多个根标签&#xff0c;如果使用<></>无法正确赋值key&#xff0c;代码如下&#xff1a; function App() {const list [{ id:1, name:"小明" },{ id:2, name:"小田" },{ id:3, name:"小王" }]const listCon…

使用VC++实现分段线性变换,直方图均衡化、锐化处理(使用拉普拉斯算子)

图像锐化1 获取源工程可访问huiningLi的gitee可在此工程的基础上进行学习。 实验要求 5.1实验目的、要求 实验目的&#xff1a; &#xff08;1&#xff09;掌握图像增强的原理与相关方法。 &#xff08;2&#xff09;能使用VC实现图像增强的一些相关功能。 实验要求&#xf…

【python】均值、中值和高斯滤波详解和示例

本文对均值、中值和高斯滤波进行详解&#xff0c;以帮助大家理解和使用。 这里写目录标题 均值滤波中值滤波高斯滤波核大小为&#xff08;9,9&#xff09;核大小为&#xff08;51,51&#xff09; 小结 下面是示例中使用的原图。 均值滤波 均值滤波是一种简单的平滑滤波器&…

PyTorch微调权威指南3:使用数据增强

如果你曾经参与过 PyTorch 模型的微调&#xff0c;可能会遇到 PyTorch 的内置变换函数&#xff0c;这使得数据增强变得轻而易举。 即使你之前没有使用过这些功能&#xff0c;也不必担心。 在本文中&#xff0c;我们将深入研究 PyTorch 变换换函数的世界。 我们将探索你可以使用…

CTFhub-RCE-过滤目录分隔符 /

根据源代码信息可知&#xff0c;过滤掉了/ <?php $res FALSE; if (isset($_GET[ip]) && $_GET[ip]) { $ip $_GET[ip]; $m []; if (!preg_match_all("/\//", $ip, $m)) { $cmd "ping -c 4 {$ip}"; exec($cmd,…

Java 实现图书管理系统

需求 编写图书借阅程序&#xff0c;可以处理简单的书籍借阅情况&#xff0c;包括借书和还书等。图书类的数据成员包括书名、书号和借书学生等&#xff1b;方法包括借书、还书和显示书籍信息等。学生类的数据成员包括姓名、学号和所借书籍等&#xff1b;方法包括显示学生信息等…