Java进击框架:Spring-Test(六)
Java进击框架:Spring-Test(六)
- 前言
- 单元测试
- 模拟对象
- 集成测试
- 上下文管理和缓存
- 事务管理
- 集成测试的支持类
- 执行SQL脚本
- WebTestClient
- MockMvc
- JDBC测试支持
- 其它注释
前言
Spring团队提倡测试驱动开发(TDD)。Spring团队发现,控制反转(IoC)的正确使用确实使单元和集成测试变得更容易(因为类上setter方法和适当构造函数的存在使它们更容易在测试中连接在一起,而不必设置服务定位器注册中心和类似的结构)。
Spring TestContext框架(位于org.springframework.test.context
包中)提供了通用的、注释驱动的单元测试和集成测试支持,与所使用的测试框架无关。TestContext框架还非常重视约定而不是配置,使用合理的默认值,您可以通过基于注释的配置来覆盖这些默认值。
该框架的核心由TestContextManager类和TestContext、TestExecutionListener和SmartContextLoader接口组成。
-
TestContextManager是Spring TestContext框架的主要入口点,负责管理单个TestContext并且向每个注册的TestExecutionListener在明确定义的测试执行点,比如:执行测试方法之前、测试方法之后。
-
TestContext封装测试运行的上下文(不知道实际使用的测试框架),并为它所负责的测试实例提供上下文管理和缓存支持。
-
TestExecutionListener定义API,用于对TestContextManager侦听器向其注册。
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyServiceTest {@Testpublic void test() throws Exception {TestContextManager testContextManager = new TestContextManager(MyServiceTest.class);testContextManager.prepareTestInstance(this);TestContext testContext = testContextManager.getTestContext();}
}
@RunWith
是 JUnit 框架提供的一个注解,用于指定测试类运行时使用的运行器(Runner)。在 Spring 中,通常会使用 SpringRunner 运行器来执行基于 Spring 的测试。它是 JUnit 4 的默认运行器,在 JUnit 5 中称为 SpringJUnit4ClassRunner。
上述示例代码中,我们创建了一个 TestContextManager 对象,并调用 prepareTestInstance(this)
方法来准备测试实例和测试上下文。通过 getTestContext()
方法获取当前测试的 TestContext 对象,我们可以使用它来操作测试上下文。
以下内容中会用的一些依赖:
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.23</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.3.23</version></dependency><!--junit 4--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope></dependency><!--junit 5--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.8.2</version><scope>test</scope></dependency><dependency><groupId>org.easymock</groupId><artifactId>easymock</artifactId><version>4.3</version><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId><version>2.4.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.4.0</version></dependency>
单元测试
与传统的J2EE / Java EE开发相比,依赖注入应该使您的代码对容器的依赖性更小。组成应用程序的POJOs在JUnit或TestNG测试中应该是可测试的,使用new操作器,不带Spring或任何其他容器。如果您遵循Spring的架构建议,那么您的代码库的干净分层和组件化有助于更容易的单元测试。例如,您可以通过存根或模仿DAO或存储库接口来测试服务层对象,而无需在运行单元测试时访问持久数据。
模拟对象
Spring包含许多专门用于mock的包。
- 环境
org.springframework.mock.env
包包含了Environment和PropertySource抽象的模拟实现。MockEnvironment和MockPropertySource对于开发依赖于环境特定属性的代码的容器外测试非常有用。
下面讲解这两种的用法,示例代码如下:
public class MyServiceTest {@Testpublic void testGetValue() {ConfigurableEnvironment mockEnv = new MockEnvironment().withProperty("my.property", "mocked value");MyService myService = new MyService();myService.setConfigurableEnvironment(mockEnv);System.out.println(myService.getValue());//断言返回的值与预期值相匹配assertEquals("mocked value2", myService.getValue());}
}
public class MyService {private String value;private ConfigurableEnvironment configurableEnvironment;public void setConfigurableEnvironment(ConfigurableEnvironment configurableEnvironment) {this.configurableEnvironment = configurableEnvironment;}public String getValue() {return configurableEnvironment.getProperty("my.property");}
}
创建了一个名为 MyService 的简单服务类,它依赖于环境变量或属性值。MyService 类中的 getValue()
方法使用了 Spring 的 ConfigurableEnvironment 对象来获取属性值。在测试中,我们使用 MockEnvironment 来模拟环境配置,并通过 setProperty()
方法设置了属性 "my.property"
的值为 "mocked value"
。
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@TestPropertySource(properties = "my.property=mocked value")
public class MyServiceTest {@Autowiredprivate MyService myService;@Testpublic void testGetValue() {String value = myService.getValue();//断言返回的值与预期值相匹配assertEquals("mocked value", value);}
}
public class MyService {@Value("${my.property}")private String myProperty;public String getValue() {return myProperty;}
}
@Configuration
public class AppConfig {@Beanpublic MyService myService() {return new MyService();}
}
通过 @TestPropertySource
注解将 MockPropertySource 添加到测试环境中,从而完成测试。需要注意的是,@TestPropertySource
注解会覆盖项目中已存在的属性源,因此在设置虚拟属性值时要确保不会意外地覆盖了其他属性。
- JNDI
JNDI 是 Java 平台提供的一种标准接口,用于访问命名和目录服务。在开发应用程序时,有时需要通过 JNDI 来获取外部资源,例如数据库连接池、消息队列等。为了方便测试这些依赖于 JNDI 的代码,可以使用 org.springframework.mock.jndi
工具包提供的模拟对象。从Spring Framework 5.2开始,软件包被正式弃用,取而代之的是来自第三方的完整解决方案,例如Simple-JNDI。
- Servlet API
org.springframework.mock.web
包包含一套全面的Servlet API模拟对象,这些对象对于测试web上下文、控制器和过滤器非常有用。这些模拟对象旨在与Spring的Web MVC框架一起使用,通常比动态模拟对象(例如EasyMock)或替代的Servlet API模拟对象(例如模拟对象)。
示例代码如下:
public class MyServiceTest {@Testpublic void testAdd() {// 创建模拟对象CalculatorService mockService = createMock(CalculatorService.class);// 设置模拟对象的期望行为expect(mockService.add(2, 3)).andReturn(5);// 将模拟对象注入到被测试类中Calculator calculator = new Calculator(mockService);// 对受测方法进行测试replay(mockService);int result = calculator.add(2, 3);// 验证期望行为是否正确响应verify(mockService);assertEquals(5, result);}
}
public interface CalculatorService {int add(int a, int b);
}
public class Calculator {private CalculatorService service;public Calculator(CalculatorService service) {this.service = service;}public int add(int a, int b) {return service.add(a, b);}
}
Spring MVC测试框架建立在模拟Servlet API对象的基础上,为Spring MVC提供了一个集成测试框架。参考MockMvc。
- Spring Web响应式
org.springframework.mock.http.server.reactive
包包含了WebFlux应用中使用的ServerHttpRequest和ServerHttpResponse的模拟实现。org.springframework.mock.web.server
包包含一个模拟ServerWebExchange,它依赖于那些模拟请求和响应对象。
MockServerHttpRequest和MockServerHttpResponse都从相同的抽象基类扩展为特定于服务器的实现,并与它们共享行为。
MockServerHttpRequest示例代码如下:
public class MyServiceTest {@Testpublic void testAdd() {// 创建一个GET请求MockServerHttpRequest request = MockServerHttpRequest.get("/api/users").header("Content-Type", "application/json").queryParam("page", "1").build();}
}
MockServerHttpResponse示例代码如下:
public class MyServiceTest {@Testpublic void testAdd() throws UnsupportedEncodingException {// 创建一个MockHttpServletResponse对象MockHttpServletResponse response = new MockHttpServletResponse();// 设置响应状态码response.setStatus(HttpServletResponse.SC_OK);// 设置响应头response.setHeader("Content-Type", "application/json");// 设置响应体内容String responseBody = "{\"message\": \"Hello, world!\"}";response.setContentLength(responseBody.length());response.getWriter().write(responseBody);// 获取响应信息int statusCode = response.getStatus();String contentType = response.getHeader("Content-Type");String responseBody2 = response.getContentAsString();}
}
Spring包含了许多有助于单元测试的类。它们分为两类:
- 通用测试工具
org.springframework.test.util
软件包包含几个通用的工具,用于单元和集成测试。
AopTestUtils是AOP相关实用方法的集合。您可以使用这些方法获得对隐藏在一个或多个Spring代理后面的底层目标对象的引用。
public class MyServiceTest {@Testpublic void testAdd() {//获取代理对象背后的最终目标对象,即被代理的真实对象。Object target = AopTestUtils.getUltimateTargetObject(MyAspect.class);System.out.println(target);// 获取代理对象的目标对象,即被代理的对象(可能是最终目标对象或者另一个代理对象)。Object target2 = AopTestUtils.getTargetObject(MyAspect.class);System.out.println(target2);}
}
ReflectionTestUtils是基于反射的实用方法的集合。您可以在需要更改常数值、设置private字段,调用一个private的setter()
方法,或者调用一个private测试应用程序代码的用例时的配置或生命周期回调方法。
public class MyServiceTest {@Testpublic void testAdd() {MyService myService = new MyService();// 使用ReflectionTestUtils设置私有字段的值ReflectionTestUtils.setField(myService, "value", "hello world");// 使用ReflectionTestUtils调用私有方法并检查返回值Object actualValue = ReflectionTestUtils.invokeMethod(myService, "getValue");System.out.println(actualValue);}
}
public class MyService {private String value;private String getValue() { return value; }public void setValue(String value) { this.value = value; }
}
TestSocketUtils可用于在可用的随机端口上启动外部服务器的集成测试。然而,这些实用程序不能保证给定端口的后续可用性,因此是不可靠的。而不是使用TestSocketUtils要为服务器找到可用的本地端口,建议您依靠服务器的能力,在它选择或由操作系统分配的随机临时端口上启动。要与该服务器交互,您应该查询服务器当前使用的端口。
- Spring MVC测试实用程序
org.springframework.test.web
包装包含ModelAndViewAssert,您可以将它与JUnit、TestNG或任何其他处理Spring MVC的单元测试框架结合使用ModelAndView对象。
public class MyServiceTest {@Testpublic void test() {ModelAndView modelAndView = new ModelAndView("myView");//使用assertViewName方法断言视图名称是否为"myView"。assertViewName(modelAndView, "myView");}
}
集成测试
能够在不需要部署到应用服务器或连接到其他企业基础设施的情况下执行一些集成测试是很重要的。这样做可以让您测试以下内容:
-
Spring IoC容器上下文的正确连接。
-
使用JDBC或ORM工具进行数据访问。这包括SQL语句的正确性、Hibernate查询、JPA实体映射等等。
Spring的集成测试支持有以下主要目标:
- 管理测试之间的Spring IoC容器缓存。
- 提供测试fixture实例的依赖注入。
- 提供适合集成测试的事务管理。
- 提供特定于spring的基类,帮助开发人员编写集成测试。
上下文管理和缓存
Spring TestContext框架提供了一致的Spring加载ApplicationContext实例和WebApplicationContext实例以及这些上下文的缓存。支持加载上下文的缓存很重要,因为启动时间会成为一个问题——不是因为Spring本身的开销,而是因为Spring容器实例化的对象需要时间来实例化。例如,一个包含50到100个Hibernate映射文件的项目可能需要10到20秒来加载映射文件,在每个测试设备中运行每个测试之前产生的成本会导致整个测试运行变慢,从而降低开发人员的工作效率。
默认情况下,一旦加载,配置的ApplicationContext将为每个测试重用。因此,每个测试套件只产生一次设置成本,并且随后的测试执行速度要快得多。在这种情况下,“测试套件”一词意味着所有测试都在同一个JVM中运行——例如,所有测试都是从给定项目或模块的Ant、Maven或Gradle构建中运行的。在不太可能的情况下,测试破坏了应用程序上下文并需要重新加载(例如,通过修改bean定义或应用程序对象的状态),TestContext框架可以配置为在执行下一个测试之前重新加载配置并重新构建应用程序上下文。
- 使用XML资源的上下文配置
使用TestContext框架的测试类不需要扩展任何特定的类或实现特定的接口来配置它们的应用程序上下文。相反,通过声明@ContextConfiguration
类级别的注释。默认情况下,则配置的ContextLoader确定如何从默认位置或默认配置类加载上下文。除了上下文资源位置和组件类,应用程序上下文也可以通过应用程序上下文初始化器来配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="myService" class="com.example.MyService"></bean>
</beans>
public class MyService {
}
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:dao.xml")
public class MyServiceTest {@AutowiredMyService myService;@Testpublic void test(){System.out.println(myService);}}
如果您@ContextConfiguration
省略了注释中的locations
和value
这两个属性,TestContext框架试图检测一个默认的XML资源位置。如果您的类被命名为com.example.MyServiceTest
,GenericXmlContextLoader加载应用程序上下文"classpath:com/example/MyServiceTest-context.xml"
。
- 使用组件类进行上下文配置
你可以用@ContextConfiguration
注释加载组件类,并用一个包含对组件类引用的数组来配置classes属性。
术语“组件类”可以指以下任何一种:
- 用注释的类
@Configuration
。- 一个组件(即一个用
@Component
,@Service
,@Repository
或者其他原型注释)。- 一个符合JSR 330标准的类,用
jakarta.inject
注释。- 任何包含以下内容的类
@Bean
-方法。- 任何其他打算注册为Spring组件的类(例如ApplicationContext),潜在地利用了单个构造函数的自动装配,而不使用Spring注释。
public class MyService {}
@Configuration
public class AppConfig {@Beanpublic MyService myService(){return new MyService();}
}
@RunWith(value = SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyServiceTest {@AutowiredMyService myService;@Testpublic void test(){System.out.println(myService);}
}
- 带有上下文初始化器的上下文配置
@ContextConfiguration
注解中的 initializers
属性用于指定要在测试上下文加载之前执行的初始化回调对象(ApplicationContextInitializer),该数组包含对实现ApplicationContextInitializer。
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println("init");}
}
@RunWith(value = SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class,initializers = MyApplicationContextInitializer.class)
public class MyServiceTest {@AutowiredMyService myService;@Testpublic void test(){System.out.println(myService);}/** Output:* init* com.example.MyService@76f2bbc1*/
}
- 上下文配置继承
@ContextConfiguration
支持布尔值inheritLocations
和inheritInitializers
指示是否应该继承由超类声明的资源位置或组件类和上下文初始值设定项的属性。两个标志的默认值都是true;设置为false时,子类必须自行定义属性值,否则会抛出 IllegalStateException 异常。
@ContextConfiguration(locations = "classpath:MyServiceTest-context.xml")
public class BaseTest {
}
@RunWith(value = SpringRunner.class)
@ContextConfiguration(inheritLocations = true)
public class MyServiceTest extends BaseTest{@AutowiredMyService myService;@Testpublic void test(){System.out.println(myService);}/** Output:* com.example.MyService@76f2bbc1*/
}
- 环境配置文件的上下文配置
Spring框架对环境和概要文件(又名“bean定义概要文件”)的概念具有一流的支持,并且可以配置集成测试来为各种测试场景激活特定的bean定义概要文件。这是通过用@ActiveProfiles
注释一个测试类,并提供一个应该在为测试加载ApplicationContext时激活的配置文件列表来实现的。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><beans profile="dev"><bean id="myService" class="com.example.MyService"><property name="value" value="dev"></property></bean></beans><beans profile="prod"><bean id="myService" class="com.example.MyService"><property name="value" value="prod"></property></bean></beans>
</beans>
public class MyService {private String value;public String getValue() { return value; }public void setValue(String value) { this.value = value; }
}
@RunWith(value = SpringRunner.class)
@ContextConfiguration
@ActiveProfiles(value = "prod")
public class MyServiceTest{@AutowiredMyService myService;@Testpublic void test(){System.out.println(myService.getValue());}/** Output:* prod*/
}
也可以使用注解的形式,示例代码如下:
@Configuration
public class AppConfig {@Bean@Profile("dev")public MyService myServiceDev(){MyService myService = new MyService();myService.setValue("dev");return myService;}@Bean@Profile("prod")public MyService myServiceProd(){MyService myService = new MyService();myService.setValue("prod");return myService;}
}
@RunWith(value = SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@ActiveProfiles(value = "prod")
public class MyServiceTest{@AutowiredMyService myService;@Testpublic void test(){System.out.println(myService.getValue());}/** Output:* prod*/
}
- 带有测试属性源的上下文配置
您可以声明@TestPropertySource
注释来声明测试属性文件或内联属性的资源位置。
name=hello
@RunWith(value = SpringRunner.class)
@TestPropertySource(locations = "/test.properties")
public class MyServiceTest{@Value("${name}")String name;@Testpublic void test(){System.out.println(name);}/** Output:* hello*/
}
通过使用@TestPropertySource
的properties属性,可以以键值对的形式配置内联属性,如下面的示例所示:
@RunWith(value = SpringRunner.class)
@TestPropertySource(locations = "/test.properties",properties = {"name:world"})
public class MyServiceTest{@Value("${name}")String name;@Testpublic void test(){System.out.println(name);}/** Output:* world*/
}
支持的语法结构有:key=value
、key:value
、key value
。
如果@TestPropertySource
被声明为空批注(也就是说,没有locations
或者properties
属性),如果带注释的测试类是com.example.MyTest
,对应的默认属性文件是classpath:com/example/MyTest.properties
。如果无法检测到默认值,则引发IllegalStateException被抛出。
- 具有动态属性源的上下文配置
从Spring Framework 5.2.5开始,TestContext框架支持动态的属性通过@DynamicPropertySource
注释。
@RunWith(value = SpringRunner.class)
@TestPropertySource(locations = "/test.properties",properties = {"name:world","name=world2"})
public class MyServiceTest{@DynamicPropertySourcestatic void redisProperties(DynamicPropertyRegistry registry) {registry.add("name", ()->"张山");}@Value("${name}")String name;@Testpublic void test(){System.out.println(name);}/** Output:* 张山*/
}
动态属性的优先级高于从@TestPropertySource
操作系统的环境、Java系统属性或由应用程序通过使用@PropertySource
或者以编程方式。
- 上下文缓存
一旦TestContext框架为一个测试加载了一个ApplicationContext(或WebApplicationContext),这个context就会被缓存并重用给所有在同一个测试套件中声明了相同唯一的context配置的后续测试。
Spring TestContext框架将应用程序上下文存储在静态缓存中。这意味着上下文实际上存储在一个静态变量中。换句话说,如果测试在单独的进程中运行,则在每次测试执行之间清除静态缓存,这将有效地禁用缓存机制。
为了从缓存机制中获益,所有测试必须在相同的进程或测试套件中运行。
- 上下文层次结构
当编写依赖加载弹簧的集成测试时ApplicationContext通常,针对单个上下文进行测试就足够了。在测试中,有时您需要创建多个嵌套的应用程序上下文,以便模拟复杂的应用程序结构或依赖关系。@ContextHierarchy
注解允许您按层次结构组织这些应用程序上下文。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextHierarchy({@ContextConfiguration("classpath:context1.xml"),@ContextConfiguration("classpath:context2.xml")
})
public class MyTest {// 测试内容
}
我们使用 @ContextHierarchy
注解来定义两个层次的应用程序上下文。第一个层次的上下文由 context1.xml 文件定义,第二个层次的上下文由 context2.xml 文件定义。这意味着 context2.xml 中的 bean 可以访问 context1.xml 中定义的 bean。
通过使用 @ContextHierarchy
注解,您可以在测试中创建多个层次的应用程序上下文,并且它们之间可以相互访问和共享 bean。这在某些复杂的测试场景下非常有用。
事务管理
在TestContext框架中,事务由TransactionalTestExecutionListener管理,它是默认配置的,即使您没有在测试类上显式声明@TestExecutionListeners
。此外,您必须在类或方法级别为您的测试声明Spring的@Transactional
注释。
TransactionalTestExecutionListener期望在Spring ApplicationContext中为测试定义一个PlatformTransactionManager bean 。如果在测试的ApplicationContext中有多个PlatformTransactionManager的实例,你可以通过使用@Transactional("myTxMgr")
或@Transactional(transactionManager = "myTxMgr")
来声明一个限定符,或者TransactionManagementConfigurer可以通过@Configuration
类来实现。
使用 XML 配置:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" />
</bean>
使用 Java 配置:
@Configuration
public class TransactionConfig {@Autowiredprivate DataSource dataSource;@Beanpublic PlatformTransactionManager transactionManager() {return new DataSourceTransactionManager(dataSource);}
}
- 启用和禁用事务
用@Transactional
注释测试方法会导致测试在事务中运行,默认情况下,该事务在测试完成后自动回滚。如果用@Transactional
注释了测试类,则该类层次结构中的每个测试方法都在事务中运行。没有使用@Transactional
注释的测试方法(在类或方法级别)不会在事务中运行。请注意,@Transactional
不支持测试生命周期方法——例如,用JUnit Jupiter的@BeforeAll
、@BeforeEach
等注释的方法。此外,带有@Transactional
注释但将传播属性设置为NOT_SUPPORTED或NEVER的测试不会在事务中运行。
@Transactional
属性支持:
属性 | 支持测试管理的事务 |
---|---|
value和transactionManager | 是 |
propagation | 仅仅Propagation.NOT_SUPPORTED和Propagation.NEVER受到支持 |
isolation | 不 |
timeout | 不 |
readOnly | 不 |
rollbackFor和rollbackForClassName | 否:使用TestTransaction.flagForRollback() 代替 |
noRollbackFor和noRollbackForClassName | 否:使用TestTransaction.flagForCommit() 代替 |
- 事务回滚和提交行为
默认情况下,测试事务将在测试完成后自动回滚;但是,事务性提交和回滚行为可以通过@Commit
和@Rollback
注释。
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MyTest {@Autowiredprivate UserRepository userRepository;@Test@Commitpublic void testCommit() {User user = new User();user.setUsername("test");user.setPassword("123456");userRepository.save(user);assertThat(userRepository.findByUsername("test")).isNotNull();}@Test@Rollbackpublic void testRollback() {User user = new User();user.setUsername("test");user.setPassword("123456");userRepository.save(user);assertThat(userRepository.findByUsername("test")).isNotNull();}
}
您可以在测试方法中、方法之前和方法之后使用TestTransaction来启动或结束当前测试管理的事务,或者为回滚或提交配置当前测试管理的事务。只要启用了TransactionalTestExecutionListener,对TestTransaction的支持就自动可用。
@RunWith(SpringRunner.class)
public class MyTest {@Autowiredprivate UserRepository userRepository;@Testpublic void testCommit() {// 开启事务TestTransaction.start();try {User user = new User();user.setUsername("test");user.setPassword("123456");userRepository.save(user);// 标记事务为回滚状态TestTransaction.flagForRollback();// 断言事务已标记为回滚状态assertTrue(TestTransaction.isFlaggedForRollback());// 结束事务并验证数据库状态TestTransaction.end();// 可以进行其他断言或验证操作} finally {// 重置事务状态,确保下一个测试方法开始时的事务状态正常TestTransaction.flagForCommit();TestTransaction.end();}}
}
有时,您可能需要在事务性测试方法之前或之后但在事务性上下文之外运行某些代码,TransactionalTestExecutionListener支持@BeforeTransaction
和@AfterTransaction
针对此类场景的注释。
@RunWith(SpringRunner.class)
@Transactional
public class MyTest {@Autowiredprivate UserRepository userRepository;@BeforeTransactionpublic void beforeTransaction() {// 在事务开启前操作}@AfterTransactionpublic void afterTransaction() {// 在事务回滚或提交后操作}@Testpublic void testSaveUser() {// 测试方法中省略具体测试逻辑}
}
集成测试的支持类
Spring TestContext框架提供了几个abstract支持简化集成测试编写的类。这些基本测试类提供了测试框架中定义良好的钩子,以及方便的实例变量和方法,让您可以访问:
-
ApplicationContext,用于执行显式bean查找或测试上下文的整体状态。
-
一个JdbcTemplate,用于执行SQL语句来查询数据库。您可以在执行与数据库相关的应用程序代码之前和之后使用这样的查询来确认数据库状态,并且Spring确保这样的查询与应用程序代码在相同的事务范围内运行。当与ORM工具一起使用时,一定要避免误报。
Spring TestContext框架提供了与JUnit 5中引入的JUnit Jupiter测试框架的完全集成。通过用注释测试类
@ExtendWith(SpringExtension.class)
,您可以实现标准的基于JUnit Jupiter的单元和集成测试,例如支持加载应用程序上下文、测试实例的依赖注入、事务性测试方法执行等等。
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { AppConfig.class })
public class MyTest {@Autowiredprivate MyService myService;@Testpublic void testMyMethod() {// 测试代码}
}
执行SQL脚本
Spring提供了以下选项,用于在集成测试方法中以编程方式执行SQL脚本。
org.springframework.jdbc.datasource.init.ScriptUtils
:提供了一组用于处理SQL脚本的静态实用工具方法,主要供框架内部使用。org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
:提供基于对象的API,通过使用外部资源中定义的SQL脚本以编程方式填充、初始化或清理数据库。org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests
org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests
@Testpublic void test() {// 创建 ResourceDatabasePopulator 实例ResourceDatabasePopulator populator = new ResourceDatabasePopulator();// 添加 SQL 脚本文件资源populator.addScript(new ClassPathResource("data.sql"));// 执行填充操作populator.execute(dataSource);}
除了上述以编程方式运行SQL脚本的机制之外,您可以声明@Sql
测试类或测试方法上的注释,用于配置单个SQL语句或SQL脚本的资源路径,这些SQL脚本应在集成测试方法之前或之后针对给定数据库运行。
@RunWith(value = SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@Sql(scripts = "create_table.sql")
public class MyServiceTest {@Test@Sql(scripts = "data.sql",statements = "需要执行的sql语句",executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)public void test() {}
}
statements
属性:添加一条新的sql。executionPhase
属性:用于指定 SQL 执行的阶段,默认情况下,executionPhase
的值为 BEFORE_TEST_METHOD,即在每个测试方法执行之前执行 SQL 脚本。除此之外还有一些其它值:AFTER_TEST_METHOD(测试方法执行之后执行),BEFORE_TEST_CLASS(测试类的所有测试方法之前执行),AFTER_TEST_CLASS(测试类的所有测试方法之后执行)。
如果没有指定SQL脚本或语句,则尝试检测default脚本,取决于位置@Sql
已声明。如果无法检测到默认值,则引发IllegalStateException被抛出。
-
类级声明:如果带注释的测试类是
com.example.MyTest
,相应的默认脚本是classpath:com/example/MyTest.sql
。 -
方法级声明:如果带注释的测试方法被命名为
testMethod()
并且在类中定义com.example.MyTest
,相应的默认脚本是classpath:com/example/MyTest.testMethod.sql
。 -
sql分组
@SqlGroup
注解可以用于对多个 @Sql
注解进行分组,从而方便地在测试类或测试方法上进行统一配置。
@RunWith(value = SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@SqlGroup({@Sql(scripts = "create_table.sql",config = @SqlConfig(commentPrefix = "#")),@Sql(scripts = "drop_table.sql")})
public class MyServiceTest {
}
- 解释sql
@SqlConfig
是一个用于配置 @Sql
注解行为的注解。它可以定义一些与 SQL 脚本执行相关的参数,例如分隔符、错误处理等。
@SqlConfig
注解不限于以下属性:
- separator:指定 SQL 脚本中的语句分隔符,默认为
";"
。你可以根据自己的需要将其设置为其他分隔符,例如"$"
或"$$"
。- commentPrefix:指定 SQL 脚本中的注释前缀,默认为
"--"
。如果你的 SQL 脚本使用了其他注释前缀,可以在此处进行配置。- errorMode:指定 SQL 脚本执行过程中遇到错误时的处理方式,默认为 ErrorMode.FAIL_ON_ERROR。可以选择的处理方式包括 FAIL_ON_ERROR、CONTINUE_ON_ERROR 和 HALT_ON_ERROR,分别表示在遇到错误时抛出异常、继续执行脚本但记录错误、或者停止执行脚本并记录错误。
@RunWith(value = SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@Sql(scripts = "create_table.sql",config = @SqlConfig(commentPrefix = "#"))
public class MyServiceTest {
}
- 合并sql
从Spring Framework 5.2开始,可以合并方法级@Sql
具有类级声明的声明,使用@SqlMergeMode
注解。
@RunWith(value = SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@SqlMergeMode(value = SqlMergeMode.MergeMode.MERGE)
public class MyServiceTest {
}
要启用@Sql
合并,请用@SqlMergeMode(MERGE)
注释测试类或测试方法。要禁用特定测试方法(或特定测试子类)的合并,您可以通过@SqlMergeMode(OVERRIDE)
切换回默认模式。
WebTestClient
WebTestClient是为测试服务器应用程序而设计的HTTP客户端。它包裹着春天的网络客户端并使用它来执行请求,但公开了用于验证响应的测试外观。WebTestClient可用于执行端到端HTTP测试。它还可以通过模拟服务器请求和响应对象,在没有运行服务器的情况下测试Spring MVC和Spring WebFlux应用程序。
- 绑定到控制器
这种设置允许您通过模拟请求和响应对象测试特定的控制器,而无需运行服务器。
对于WebFlux应用程序,使用下面的代码来加载与WebFlux Java配置注册给定的控制器,并创建一个WebHandler链要处理请求:
WebTestClient client = WebTestClient.bindToController(new TestController()).build();
对于Spring MVC,使用下面的代码StandaloneMockMvcBuilder加载等效于WebMvc Java配置注册给定的控制器,并创建MockMvc要处理请求:
WebTestClient client = MockMvcWebTestClient.bindToController(new TestController()).build();
你还可以绑定到ApplicationContext:
@RunWith(SpringRunner.class)
@WebAppConfiguration
public class MyServiceTest {@Autowiredprivate WebApplicationContext webApplicationContext;@Testpublic void test() {WebTestClient client = MockMvcWebTestClient.bindToApplicationContext(webApplicationContext).build();}
}
如果你使用ApplicationContext进行绑定,推荐使用@RunWith(SpringRunner.class)
和@WebAppConfiguration
,启动你的测试用例,防止意外的错误。
绑定到路由器功能:
RouterFunction<?> route = ...
client = WebTestClient.bindToRouterFunction(route).build();
绑定到服务器:
WebTestClient client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build();
- 客户端配置
@WebFluxTest
public class MyServiceTest {@Testpublic void test() {WebTestClient build = WebTestClient.bindToController(new TestController()).configureClient().baseUrl("/test").build();}
}
我们使用 configureClient()
方法为 WebTestClient 实例进行配置,并通过 baseUrl()
方法设置基本 URL。最后,使用 build()
方法创建 WebTestClient 对象并将其分配给 build 变量。
- 执行请求
WebTestClient提供了一个与WebClient相同的API,直到使用exchange()
执行请求。在调用exchange()
之后,WebTestClient从WebClient中分离出来,继续使用工作流来验证响应。
@WebFluxTest
public class MyServiceTest {@Testpublic void test() {WebTestClient build = WebTestClient.bindToController(new TestController()).configureClient().baseUrl("/test").build();WebTestClient.ResponseSpec response = build.get()//请求方式.uri("/method")//请求地址.exchange();//执行请求}
}
除此之外还有其他的方法,设置请求参数、请求头,示例代码如下:
@WebFluxTest
public class MyServiceTest {@Testpublic void test() {WebTestClient build = WebTestClient.bindToController(new TestController()).configureClient().baseUrl("/test").build();WebTestClient.ResponseSpec response = build.post()//请求方式.uri("/method")//请求地址.bodyValue(new Object())//设置请求参数.accept(MediaType.APPLICATION_JSON)//设置请求头格式.exchange()//执行请求;}
}
- 响应处理
我们还可以使用断言来进行响应的判断
@WebFluxTest
public class MyServiceTest {@Testpublic void test() {WebTestClient build = WebTestClient.bindToController(new TestController()).configureClient().baseUrl("/test").build();List response = build.post().uri("/method").exchange().expectStatus().isOk()//断言方式,用于验证期望的 HTTP 响应状态码是否为 200(OK)。除此之外还有其他比如404、500等.expectHeader().contentType(MediaType.APPLICATION_JSON)//设置响应头格式.expectBody(List.class).consumeWith(result->{//响应体的内容//如果内置断言不够,您可以使用该对象并执行任何其他断言:})//.returnResult()//将响应结果转换为 EntityExchangeResult 对象,可以通过该对象获取响应状态码、响应头、响应体等信息.getResponseBody()//获取实体对象;}
}
expectStatus()
还有其他的一些用途,如下:
.isOk()
:断言状态码是否为 200。
.isNotFound()
:断言状态码是否为 404。
.is5xxServerError()
:断言状态码是否为 5xx(服务器错误)。
.value(int expectedStatus)
:断言状态码是否等于 expectedStatus。
expectBody()
方法还有其他的一些用途,如下:
expectBody().isEmpty()
:验证响应体是否为空。
expectBody().json(String expectedJson)
:验证响应体的 JSON 内容是否与预期一致。
expectBody().jsonPath(String expression, Object... args)
:使用 JSONPath 表达式来验证响应体中的字段值。
expectBody().isEqualTo(Object expectedObject)
:验证响应体是否与预期对象完全相等。
如果您想忽略响应内容,可以使用.expectBody(Void.class)
(上述代码都是经过测试成功跑通的示例,不同的注解有点区别)
MockMvc
Spring MVC测试框架,也称为MockMvc,旨在为Spring MVC控制器提供更完整的测试,而无需运行服务器。Spring -test模块在没有运行服务器的情况下复制了完整的Spring MVC请求处理。
MockMvc可以单独用于执行请求和验证响应。它也可以通过WebTestClient使用,其中插入MockMvc作为处理请求的服务器。WebTestClient的优点是可以使用更高级的对象而不是原始数据,还可以切换到针对活动服务器的完整端到端HTTP测试,并使用相同的测试API。
要设置MockMvc来测试一个特定的控制器,使用以下代码:
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
MockMvcBuilders是Spring MVC Test框架提供的工厂类,用于创建MockMvc实例。
你也可以使用ApplicationContext:
@RunWith(SpringRunner.class)
@WebAppConfiguration
public class MyServiceTest {@Autowiredprivate WebApplicationContext webApplicationContext;@Testpublic void test() {MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();}
}
如果你使用ApplicationContext进行启动,推荐使用@RunWith(SpringRunner.class)
和@WebAppConfiguration
,启动你的测试用例,防止意外的错误。
- 执行请求
@WebFluxTest
public class MyServiceTest {@Testpublic void test() {//standaloneSetup是一个静态方法可以直接调用standaloneSetup(new TestController()).build();MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();try {mockMvc.perform(post("/test/method/{id}",1)//请求方式:get()、post(),方法中第二参数可以传参.accept(MediaType.APPLICATION_JSON)//请求头:除了accept()方法还有contentType()方法、header()方法都可以设置请求头.param("name","test")//传参指定字段.content("{\"name\": \"test\", \"age\": 18}")//传参,json格式);} catch (Exception e) {e.printStackTrace();}}
}
通过上述示例,我们可以知道,传参方式有三种,可以在请求方法中添加第二个参数、也可以调用.param()
方法或者.content()
方法。
- 响应处理
我们可以对响应进行一些处理,andExpect()
方法来验证模型中是否存在错误属性。
@WebFluxTest
public class MyServiceTest {@Testpublic void test() {MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();try {MvcResult person = mockMvc.perform(get("/test/method")).andExpect(status().isOk())//用于验证期望的 HTTP 响应状态码是否为 200(OK)。除此之外还有其他比如404、500等.andExpect(content().contentType(MediaType.APPLICATION_JSON))//设置响应头格式.andExpect(model().attributeHasErrors("person"))//验证模型中是否存在错误属性.andReturn();//获取执行请求后的返回结果String contentAsString = person.getResponse().getContentAsString();} catch (Exception e) {e.printStackTrace();}}
}
除了使用 .getContentAsString()
方法获取响应体以字符串形式,MvcResult 还提供了其他方法来获取不同类型的响应数据,比如 .getResponse().getContentAsByteArray()
可以获取响应体以字节数组形式,.getResponse().getHeader()
可以获取响应头信息等。
- 筛选注册
当设置一个MockMvc实例时,你可以注册一个或多个Servlet Filter实例,如下例所示:
@WebFluxTest
public class MyServiceTest {@Testpublic void test() {MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).addFilter(new CharacterEncodingFilter()).build();}
}
- html单元集成
Spring提供了MockMvc和HtmlUnit。当使用基于HTML的视图时,这简化了端到端测试的执行(现在大多数项目都是前后分离项目,所以并不建议增加后端测试用例的工作量,如果有需要可以自行了解)。
MockMvc适用于不依赖于Servlet容器的模板技术(例如,Thymeleaf、FreeMarker等),但不适用于JSP,因为它们依赖于Servlet容器。
JDBC测试支持
org.springframework.test.jdbc
包装包含JdbcTestUtils,这是一个与JDBC相关的实用函数集合,旨在简化标准数据库测试场景。具体来说,JdbcTestUtils提供下列静态实用工具方法。
countRowsInTable(..)
:计算给定表中的行数。countRowsInTableWhere(..)
:使用提供的计算给定表中的行数WHERE条件。deleteFromTables(..)
:删除指定表中的所有行。deleteFromTableWhere(..)
:使用提供的从给定的表中删除行WHERE条件。dropTables(..)
:删除指定的表。
其它注释
除了前面内容中介绍过的注解,再来讲解下没用到的一些注解(你不必全都记住,只要会一两种能解决你的问题即可)。
@ContextConfiguration
注解
@ContextConfiguration
定义类级元数据,该元数据用于确定如何加载和配置ApplicationContext用于集成测试。具体来说,@ContextConfiguration
声明应用程序上下文资源locations或者组件classes用于加载上下文。
//@ContextConfiguration(locations = { "classpath:/applicationContext.xml" })使用 XML 文件配置
//@ContextConfiguration(locations = { "classpath:/com/example/app/" })使用组件扫描
@ContextConfiguration(classes = { AppConfig.class })//使用 Java 配置类
public class MyServiceTest {
}
@WebAppConfiguration
注解
@WebAppConfiguration
是一个类级别的注释,你可以用它来声明为集成测试加载的ApplicationContext应该是一个WebApplicationContext。
@WebAppConfiguration
@ContextConfiguration
public class MyServiceTest {
}
@ContextHierarchy
注解
@ContextHierarchy
是一个类级注释,用于定义ApplicationContext集成测试的实例。@ContextHierarchy
应该用一个或多个@ContextConfiguration
实例,每个实例定义上下文层次结构中的一个级别。
@Configuration
@ContextHierarchy({@ContextConfiguration(classes = AppConfig.class),@ContextConfiguration(classes = DatabaseConfig.class)
})
public class RootConfig {// ...
}
@DirtiesContext
注解
@DirtiesContext
注解用于标记测试方法或类会导致应用程序上下文被"脏化"(dirty)。当一个测试方法或类被标记为 @DirtiesContext
时,在执行该方法或类后,Spring 将会重置相应的应用程序上下文,以确保下一个测试方法或类在一个干净的环境中运行。
@RunWith(SpringRunner.class)
public class MyServiceTest {@Test@DirtiesContextpublic void testMethod() {// ...}@Testpublic void anotherTestMethod() {// ...}
}
@TestExecutionListeners
注解
@TestExecutionListeners
用于自定义测试执行时的监听器。通过使用 @TestExecutionListeners
注解,我们可以指定在测试方法或类执行期间调用的监听器,以扩展测试框架的功能或添加额外的行为。
测试执行监听器可以实现 TestExecutionListener 接口或继承 TestExecutionListenerAdapter 类,并覆盖其中的方法来定义自定义的测试执行行为。
public class MyTestListener implements TestExecutionListener {@Overridepublic void beforeTestMethod(TestContext testContext) throws Exception {// 在测试方法执行之前执行的逻辑System.out.println("after");}
}
@RunWith(SpringRunner.class)
@TestExecutionListeners({ MyTestListener.class })
public class MyServiceTest {@Testpublic void test() {System.out.println("test");}
}
@Timed
注解
在JUnit 4中,通过使用 @Timed
注解,指示带注释的测试方法必须在指定的时间段(以毫秒为单位)内完成执行。如果文本执行时间超过指定的时间段,测试失败。
@RunWith(SpringRunner.class)
public class MyServiceTest {@Test@Timed(millis = 10)public void test() {System.out.println("qwe");}
}
@Repeat
注解
在JUnit 4中,指示带注释的测试方法必须重复运行。注释中指定了测试方法的运行次数。
@RunWith(SpringRunner.class)
public class MyServiceTest {@Test@Repeat(5)public void test() {System.out.println("qwe");}
}
@SpringJUnitConfig
注解
@SpringJUnitConfig
是 JUnit 5 中的一个组合注释,它结合了@ExtendWith(SpringExtension.class)
和Spring TestContext框架中的@ContextConfiguration
,我们可以方便地将 Spring 的功能集成到JUnit测试中,并使用 Spring 上下文来管理测试环境和依赖注入。
@SpringJUnitConfig(AppConfig.class)
public class MyServiceTest {
}
@SpringJUnitWebConfig
注解
@SpringJUnitWebConfig
是 JUnit 5 中的一个组合注释,它结合了JUnit Jupiter中的@ExtendWith(SpringExtension.class)
和Spring TestContext框架中的@ContextConfiguration
和@WebAppConfiguration
。
@SpringJUnitWebConfig(TestController.class)
public class MyServiceTest {
}
上面介绍的一些*Config
注解在实际测试中有很多问题,可能是依赖版本导致不支持,已经可以跑通的还是JUnit 4版本,示例代码:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyServiceTest {@Autowiredprivate ApplicationContext applicationContext;@Autowiredprivate MyService myService;@Testpublic void test() {System.out.println(myService);System.out.println(applicationContext);}
}
如果你想使用WebApplicationContext 做一些处理,可以使用@WebAppConfiguration
注解,示例代码如下:
@RunWith(SpringRunner.class)
@WebAppConfiguration
public class MyServiceTest {@Autowiredprivate WebApplicationContext applicationContext;@Autowiredprivate MyService myService;@Testpublic void test() {System.out.println(myService);System.out.println(applicationContext);}
}
如果你有更好的使用方法,欢迎评论区讨论交流。
相关文章:

Java进击框架:Spring-Test(六)
Java进击框架:Spring-Test(六) 前言单元测试模拟对象 集成测试上下文管理和缓存事务管理集成测试的支持类执行SQL脚本WebTestClientMockMvc JDBC测试支持其它注释 前言 Spring团队提倡测试驱动开发(TDD)。Spring团队发现,控制反转…...

微软:Octo Tempest是最危险的金融黑客组织之一
导语 最近,微软发布了一份关于金融黑客组织Octo Tempest的详细报告。这个组织以其高级社交工程能力而闻名,专门针对从事数据勒索和勒索软件攻击的企业。Octo Tempest的攻击手段不断演变,目标范围也不断扩大,成为了电缆电信、电子邮…...

JS加密/解密之逻辑运算符加密进阶篇
前言 前篇给大家介绍了运算符不为人知的基础知识。他们的各种表达形式,今天我们从这个基础上,继续进一步告诉大家,如何对字符串进行加密处理。还是那句话,技术人不废话,直接晒代码。 示例源代码 // 字符串加密示…...

【ROS入门】机器人系统仿真——URDF集成Gazebo
文章结构 URDF与Gazebo基本集成流程创建功能包编写URDF或Xacro文件启动 Gazebo 并显示机器人模型 URDF集成Gazebo相关设置collisioninertial颜色设置 URDF集成Gazebo实操编写封装惯性矩阵算法的 xacro 文件复制相关 xacro 文件,并设置 collision inertial 以及 colo…...

互联多区域电网的负荷频率控制研究
摘要 电力行业的发展程度是衡量国民经济水平以及国家安全保障的一项重要指标。多区域负荷频率控制系统作为现代电力系统发展的重要趋势,在可靠性、经济性和稳定性上都具备一定的优势。保证系统稳定和输出电能的质量是电网运行的关键。电力系统输出电能质量的优劣取决…...

【java学习—九】模板方法(TemplateMethod)设计模式(4)
文章目录 1. 在java中什么是模板2. 模板方法设计解决了什么问题?3. 代码化理解 1. 在java中什么是模板 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留…...

【MyBatis Plus】初识 MyBatis Plus,在 Spring Boot 项目中集成 MyBatis Plus,理解常用注解以及常见配置
文章目录 一、初识 MyBatis Plus1.1 MyBatis Plus 是什么1.2 MyBatis Plus 和 MyBatis 的区别 二、在 Spring Boot 项目中集成 MyBatis Plus2.1 环境准备2.2 引入 MyBatis Plus 依赖2.3 定义 Mapper2.4 测试 MyBatis Plus 的使用 三、MyBatis Plus 常用注解3.1 为什么需要注解3…...

Centos7 安装和配置 Redis 5 教程
在Centos上安装Redis 5,如果是 Centos8,那么 yum 仓库中默认的 redis 版本就是 5,直接 yum install 即可。但如果是 Centos7,yum 仓库中默认的 redis 版本是 3 系列,比较老: 通过 yum list | grep redis 命…...

使用 RAG、Langchain 和 Streamlit 制作用于文档问答的 AI 聊天机器人
在这篇文章中,我们将探索创建一个简单但有效的聊天机器人,该机器人根据上传的 PDF 或文本文件的内容响应查询。该聊天机器人使用 Langchain、FAISS 和 OpenAI 的 GPT-4 构建,将为文档查询提供友好的界面,同时保持对话上下文完整。…...

论文阅读——RoBERTa
一、LM效果好但是各种方法之间细致比较有挑战性,因为训练耗费资源多、并且在私有的不同大小的数据集上训练,不同超参数选择对结果影响很大。使用复制研究的方法对BERT预训练的超参数和数据集的影响细致研究,发现BERT训练不够,提出…...

springboot项目打jar包,运行时提示jar中没有主清单属性
可能性一: 没有在pom中加入maven插件 在pom中加入下方代码即可。 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</ve…...

【Codeforces】 CF79D Password
题目链接 CF方向 Luogu方向 题目解法 看到区间异或,一个经典的套路是做差分,我们即在 l l l 处异或一次,在 r 1 r1 r1 处异或一次,然后前缀和起来 于是我们可以将问题转化成:有一个序列初始全 0 0 0,…...

叛乱沙漠风暴server安装 ubuntu 22.04
最新版沙暴已经不支持centos了,还是使用ubuntu比较顺利 官方文档: https://sandstorm-support.newworldinteractive.com/hc/en-us/articles/360049211072-Server-Admin-Guide // 安装steamcmd依赖 sudo add-apt-repository multiverse sudo apt inst…...

ES6中的新增属性——解构赋值
首先我们要创建一个假数据,我们现在要取出user中的id和名称,如下: let user JSON.parse(sessionStorage.getItem(userInfo)) let id user.id; let name user.name; 非常的麻烦,我们需要一项一项的获取,这个时候可…...

行业追踪,2023-10-27
自动复盘 2023-10-27 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…...

Qt QWebEngine 更换语言
背景 使用Qt QWebEngine开发的应用,在一些场景下,会显示英文文本,比如右键、JS弹出的对话框,所以需要进行汉化,更改语言。 准备翻译文件 Qt有提供翻译好的ts文件,我们可以直接下载ts文件qtwebengine_zh_…...

Docker一键开启、停止和删除所有容器
开启所有运行的容器: docker start $(docker ps -aq) 这里,docker ps -aq 列出了所有容器的ID,然后 docker start 命令用于开启这些容器。 停止所有运行的容器: docker stop $(docker ps -aq) 同理,docker ps -aq…...

2016年亚太杯APMCM数学建模大赛B题化学元素对变形钢筋性能的影响求解全过程文档及程序
2016年亚太杯APMCM数学建模大赛 B题 化学元素对变形钢筋性能的影响 原题再现 热轧带肋钢筋通常被称为变形钢筋,它主要用于钢筋混凝土构件的骨架,在使用中需要一定的机械强度、弯曲和变形性能、制造焊接性。钢中的化学成分是影响热轧钢最终组织性能的基…...

美颜SDK集成指南:为应用添加视频美颜功能
随着社交媒体和直播应用的兴起,视频美颜功能已成为用户追求的一项热门特性。用户希望能够在拍摄照片或进行实时视频直播时,使用美颜功能来增强其外观。为了满足这一需求,开发者可以考虑集成美颜SDK,为其应用增加这一吸引人的功能。…...

AquilaChat2-34B 主观评测接近GPT3.5水平,最新版本Base和Chat权重已开源!
两周前,智源研究院发布了最强开源中英双语大模型AquilaChat2-34B 并在 22项评测基准中综合能力领先,广受好评。为了方便开发者在低资源上运行 34B 模型,智源团队发布了 Int4量化版本,AquilaChat2-34B 模型用7B量级模型相近的GPU资…...

useGeneratedKeys=“true“ keyProperty=“id“
1、xml中 useGeneratedKeys"true" keyProperty"id"2、db id bigint(20) AUTO_INCREMENT 3、场景 一般用于 先将DO写入dbinsert成功后,再将JDBC自增主键值AUTO_INCREMENT,回写到DO的id属性字段后续可能会从DO中获取此id值进行查询…...

Java 浅拷贝会带来的问题
Java 浅拷贝会带来的问题 一,常见问题 Java 中的浅拷贝是指在对象拷贝时,只复制对象的引用,而不是对象本身。这意味着浅拷贝会导致多个对象共享同一块内存空间,当一个对象修改共享内存时,其他对象也会受到影响。 下…...

Monocle 3 | 太牛了!单细胞必学R包!~(二)(寻找marker及注释细胞)
1写在前面 昨天又是不睡觉的一天,晚上还被家属讲了一通,理由是我去急诊了,没有在办公室待着,他老公疼没人去看。🫠 我的解释是只有我一个值班医生,不可能那么及时,而且也不是什么急症啊。&#…...

简述JVM
文章目录 JVM简介JVM运行时数据区堆(线程共享)方法区/元空间/元数据区(线程共享)栈程序计数器 JVM类加载类加载过程双亲委派模型 垃圾回收机制(GC)判断对象是否为垃圾判断是否被引用指向 如何清理垃圾, 释放对象? JVM简介 JVM 是 Java Virtual Machine 的简称, 意为Java虚拟机…...

【多线程面试题 六】、 如何实现线程同步?
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官: 如何实现线程同步&…...

地面文物古迹保护方案,用科技为文物古迹撑起“智慧伞”
一、行业背景 当前,文物保护单位的安防系统现状存在各种管理弊端,安防系统没有统一的平台,系统功能不足、建设标准不同,产品和技术多样,导致各系统独立,无法联动,形成了“信息孤岛”。地面文物…...

k8s之Flannel网络插件安装提示forbidden无权限
一、问题描述 在安装k8s的网络插件时,提示如下信息,各种forbidden无权限 [rootzzyk8s01 scripts]# kubectl apply -f kube-flannel.yml Error from server (Forbidden): error when retrieving current configuration of: Resource: "policy/v1b…...

在微信小程序云开发中引入Vant Weapp组件库
介绍 Vant 是一个轻量、可靠的移动端组件库,于 2017 年开源。 目前 Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本,并由社区团队维护 React 版本和支付宝小程序版本。 介绍 - Vant Weapp (youzan.github.io) Vant Weapp需要安装 node.js&…...

Vue+ElementUI项目打包部署到Ubuntu服务器中
1、修改config/index.js中的assetsPublicPath: /,修改为assetsPublicPath: ./ assetsPublicPath: ./2、在build/utils.js中增加publicPath: ../../ publicPath: ../../3、打开终端,在根目录下执行npm run build进行打包,打包成功后会生成dist npm run…...

面试题收集——Java基础部分(一)
1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。 2、Java有没有goto? java中的保留字…...