网站设计主要做什么,黑龙江建设网官网手机版,深圳品牌策划公司推荐,环保设备网站怎么做1. JUnit 5 基础
JUnit 5是最新的JUnit版本#xff0c;它引入了许多新特性#xff0c;包括更灵活的测试实例生命周期、参数化测试、更丰富的断言和假设等。
1.1 基本注解
Test#xff1a;标记一个方法为测试方法。BeforeEach#xff1a;在每个测试方法之前执行。AfterEa…1. JUnit 5 基础
JUnit 5是最新的JUnit版本它引入了许多新特性包括更灵活的测试实例生命周期、参数化测试、更丰富的断言和假设等。
1.1 基本注解
Test标记一个方法为测试方法。BeforeEach在每个测试方法之前执行。AfterEach在每个测试方法之后执行。BeforeAll在所有测试方法之前执行一次必须是静态方法。AfterAll在所有测试方法之后执行一次必须是静态方法。DisplayName定义测试类或测试方法的自定义名称。Nested允许将测试类分组到更小的测试类中。ParameterizedTest进行参数化测试。
1.2 断言Assertions类
Assertions 类是JUnit 5中用于断言的核心类提供了一系列静态方法来验证测试条件是否满足预期。
assertEquals(expected, actual)验证两个对象是否相等。如果不等测试失败。assertTrue(boolean condition)验证条件是否为真。如果为假测试失败。assertFalse(boolean condition)验证条件是否为假。如果为真测试失败。assertNull(Object object)验证对象是否为null。如果不为null测试失败。assertNotNull(Object object)验证对象是否不为null。如果为null测试失败。assertThrows(ClassT expectedType, Executable executable)验证执行executable是否抛出了expectedType类型的异常。如果没有抛出或抛出其他类型的异常测试失败。assertAll(Executable... executables)同时执行多个断言如果所有断言都成功则测试通过如果任何一个断言失败所有失败的断言都会被报告。assertSame(expected, actual)验证两个对象是否为同一个对象使用比较。如果不是测试失败。assertNotSame(unexpected, actual)验证两个对象是否不是同一个对象使用比较。如果是测试失败。assertTimeout(Duration timeout, Executable executable)验证执行executable是否在给定的时间内完成。如果执行超时测试失败。
1.3 Assumptions 类
Assumptions 类提供了基于某些条件判断是否执行测试的能力。如果假设失败即条件不满足当前测试会被跳过而不是失败。以下是一些常用的Assumptions方法
assumeTrue(boolean assumption)如果假设为真则继续执行测试如果假设为假测试被跳过。assumeFalse(boolean assumption)如果假设为假则继续执行测试如果假设为真测试被跳过。assumingThat(boolean assumption, Executable executable)如果假设为真则执行给定的executable可以是一个测试方法无论假设结果如何测试都会继续执行但executable只在假设为真时执行。
2.Mockito 基础
Mockito是一个流行的Java mocking框架用于在隔离环境中测试代码通过模拟依赖来确保测试的独立性。 基本注解 Mock创建一个模拟对象。InjectMocks创建一个实例其字段或构造器依赖将被Mock注解的模拟对象自动注入。Spy可以创建一个真实的对象并在需要时对它的某些方法进行模拟。Captor用于捕获方法调用的参数。 常用方法 mock(ClassT classToMock)创建一个类的模拟对象。这是创建模拟对象的基础。 when(T methodCall)当你想模拟一个方法调用的返回值时使用。与thenReturn一起使用可以指定一个方法调用应该返回什么值。 thenReturn(T value)与when方法一起使用用于指定方法调用的返回值。 doReturn(Object toBeReturned)一个替代thenReturn的方法用在当你需要模拟void方法或在spy对象上进行模拟时。 verify(T mock)用于验证某个模拟对象的某个方法是否被调用以及调用的次数。 any()在设定模拟行为如when或验证如verify时用于表示任何类型和值的参数。 eq(T value)用于指定方法调用时期望的具体参数值。 doNothing()用于模拟void方法时指定该方法不执行任何操作。 doThrow(Throwable... toBeThrown)用于模拟方法调用时抛出异常。 spy(T object)创建一个真实对象的“间谍”或“spy”。这允许你在真实对象上“监视”方法调用同时还能够覆盖某些方法的行为。 ArgumentCaptorT用于捕获方法调用时传递的参数以便后续进行断言。 times(int wantedNumberOfInvocations)与verify方法一起使用用于指定某个方法被调用的具体次数。 never()与verify一起使用用于验证某个方法从未被调用过。
示例
假设我们有一个PaymentService类它依赖于PaymentProcessor接口
public class PaymentService {private PaymentProcessor processor;public PaymentService(PaymentProcessor processor) {this.processor processor;}public boolean process(double amount) {return processor.processPayment(amount);}
}
下面是如何使用JUnit 5和Mockito来测试PaymentService类
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;ExtendWith(MockitoExtension.class)
public class PaymentServiceTest {MockPaymentProcessor processor;Testpublic void testProcessPayment() {// 设置PaymentService service new PaymentService(processor);double amount 100.0;when(processor.processPayment(amount)).thenReturn(true);// 执行boolean result service.process(amount);// 验证assertTrue(result);verify(processor).processPayment(amount);}
}在这个例子中我们使用Mock来创建PaymentProcessor的模拟对象并使用when(...).thenReturn(...)来定义当调用processPayment方法时应返回的值。然后我们执行process方法并使用assertTrue来验证结果是否符合预期。最后我们使用verify来确认processPayment方法是否被正确调用。
3.JUnit 5 进阶用法
参数化测试Parameterized Tests
参数化测试允许你使用不同的参数多次运行同一个测试。这对于需要验证多种输入条件的方法特别有用。
ParameterizedTest
ValueSource(strings {Hello, JUnit})
void withValueSource(String word) {assertNotNull(word);
}
动态测试Dynamic Tests
JUnit 5允许你动态生成测试这些测试可以在运行时根据代码逻辑来决定。
TestFactory
CollectionDynamicTest dynamicTests() {return Arrays.asList(dynamicTest(Add test, () - assertEquals(2, Math.addExact(1, 1))),dynamicTest(Multiply Test, () - assertEquals(4, Math.multiplyExact(2, 2))));
}
嵌套测试Nested Tests
使用Nested注解你可以将相关的测试组织在一起作为一个组在外层测试类中运行。
Nested
class WhenNew {Testvoid isEmpty() {assertEquals(0, new ArrayList().size());}
Nestedclass AfterAddingAnElement {Testvoid isNotEmpty() {ListObject list new ArrayList();list.add(new Object());
assertEquals(1, list.size());}}
} 超时测试
JUnit 5允许你为测试设置超时时间确保测试在给定时间内完成。如果超出指定时间测试将失败。
Test
Timeout(value 500, unit TimeUnit.MILLISECONDS)
void timeoutTest() {// 模拟一个耗时的操作// 如果操作超过500毫秒则测试失败
}
重复测试
如果你想对一个测试方法进行多次执行以确保其稳定性或寻找潜在的偶发问题可以使用RepeatedTest注解。
RepeatedTest(5)
void repeatTest() {// 这个测试会运行5次
}
条件执行
JUnit 5提供了多种条件执行测试的方法这些方法可以基于不同的条件来决定是否执行某个测试例如操作系统类型、环境变量或Java版本。
Test
EnabledOnOs(OS.WINDOWS)
void onlyOnWindows() {// 仅在Windows操作系统上运行
}
Test
EnabledIfSystemProperty(named user.name, matches yourUserName)
void onlyForSpecificUser() {// 仅当系统用户名匹配时运行
} 4.Mockito 进阶用法
使用Spy进行部分模拟
有时你可能需要模拟类的某些方法而保持其他方法的实际行为。Spy注解允许你这样做。
Spy
ListString spyList new ArrayList();
Test
void testSpy() {spyList.add(one);spyList.add(two);
verify(spyList).add(one);verify(spyList).add(two);
assertEquals(2, spyList.size()); // 实际调用方法
// 修改方法行为doReturn(100).when(spyList).size();assertEquals(100, spyList.size()); // 方法行为被改变
}
参数捕获Argument Captors
有时在验证方法调用时你可能对方法调用的具体参数值感兴趣。Captor注解和ArgumentCaptor类允许你捕获和检查这些值。
Mock
ListString mockList;
Captor
ArgumentCaptorString argCaptor;
Test
void argumentCaptorTest() {mockList.add(one);verify(mockList).add(argCaptor.capture());
assertEquals(one, argCaptor.getValue());
}
连续调用的不同返回值
有时候你可能需要一个方法在连续调用时返回不同的值。Mockito允许你通过thenReturn()方法链来实现这一点。
when(mockList.size()).thenReturn(0).thenReturn(1);
assertEquals(0, mockList.size());
assertEquals(1, mockList.size());
验证调用次数
验证一个方法被调用了特定次数。
mockList.add(once);
mockList.add(twice);
mockList.add(twice);
verify(mockList).add(once);
verify(mockList, times(2)).add(twice);
verify(mockList, never()).add(never happened); 模拟静态方法需要Mockito 3.4.0及以上版本
从Mockito 3.4.0开始你可以使用mockStatic来模拟静态方法。这是通过try-with-resources语句来实现的以确保静态mock在使用后被正确关闭。
try (MockedStaticUtilityClass mockedStatic mockStatic(UtilityClass.class)) {mockedStatic.when(UtilityClass::someStaticMethod).thenReturn(mocked response);assertEquals(mocked response, UtilityClass.someStaticMethod());// 静态方法被模拟期间的行为
}
// 在这个块之外静态方法恢复原有行为
模拟final方法和类
Mockito 2.x开始支持模拟final方法和类。为了启用这个功能你需要在src/test/resources/mockito-extensions目录下创建一个名为org.mockito.plugins.MockMaker的文件并在文件中添加一行内容
mock-maker-inline
这样配置后Mockito就可以模拟final类和方法了。
使用BDDMockito进行行为驱动开发
BDDMockito提供了一种基于行为驱动开发BDD的语法来编写Mockito测试使得测试更加可读。
Test
void bddStyleTest() {// 给定BDDMockito.given(mockList.size()).willReturn(2);
// 当int size mockList.size();
// 那么BDDMockito.then(mockList).should().size();assertEquals(2, size);
}
5. Mock 、InjectMocks的原理
Mock
原理Mock注解告诉Mockito框架为标注的字段生成一个模拟对象。这个模拟对象是动态生成的代理对象它拦截对任何非final方法的调用并允许测试者通过Mockito的API来配置这些调用的行为例如返回特定的值或抛出异常。如何工作当测试初始化时例如通过使用MockitoAnnotations.initMocks(this)方法或JUnit 5的ExtendWith(MockitoExtension.class)Mockito会扫描测试类中所有使用Mock注解的字段并为它们创建模拟对象。这些模拟对象默认不执行任何实际的代码逻辑它们的行为完全由测试者通过Mockito的API来控制。
InjectMocks
原理InjectMocks注解用于自动将Mock或Spy注解创建的模拟对象注入到被注解的字段中。Mockito会尝试通过构造器注入、属性注入或setter方法注入的方式将模拟对象注入到InjectMocks标注的实例中。如何工作 构造器注入Mockito首先尝试使用包含最多参数的构造器来创建实例。如果构造器的参数能够与已声明的模拟对象匹配这些模拟对象将被用作构造器参数。属性注入如果构造器注入不适用或不成功Mockito会尝试直接设置实例中与模拟对象类型相匹配的属性。Setter注入最后如果属性注入不成功Mockito会尝试通过调用匹配的setter方法来注入模拟对象。