Java中Method类和Constructor类的小测试

本文通过一个具体的Java程序示例,详细介绍了如何使用Java反射机制来获取类的构造器和方法,并进行实例化及方法调用的过程。同时,还探讨了Method类与Constructor类之间的区别,澄清了构造器与构造方法的概念混淆。


 import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Test {
 // 无参构造器
 public Test() {
  System.out.println("用无参构造器实例化了一个对象。");
 }

 // 有参构造器
 public Test(String s) {
  System.out.println("用有参构造器实例化了一个对象。参数为" + s);
 }

 // 无参方法
 public void method() {
  System.out.println("执行了无参方法。");
 }

 // 有参方法
 public void method(String s) {
  System.out.println("执行了有参方法。参数为:" + s);
 }

 public static void main(String[] args) throws Exception {
  Class testClass = Class.forName("Test");
  // 实例化一个对象,此时会调用无参构造器
  Object testObj1 = testClass.newInstance();
  // 获得带一个参数的构造器
  Constructor testConstructor = testClass.getConstructor(String.class);
  // 输出构造器的name
  System.out.println("构造器名:" + testConstructor.getName());
  // 用一个参数实例化一个对象
  Object testObj2 = testConstructor.newInstance("yuanjb");
  // 获得类的无参方法
  Method methodA = testClass.getMethod("method", null);
  // 输出方法名
  System.out.println("方法名:" + methodA.getName());
  // 调用无参方法
  methodA.invoke(testObj2, null);
  // 获得类的有参方法
  Method methodB = testClass.getMethod("method", String.class);
  // 调用有参方法
  methodB.invoke(testObj2, "parameter");

  try {
   // 尝试调用构造方法(构造器)
   // 获得类的构造方法
   Method methodC = testClass.getMethod(testConstructor.getName(),
     String.class);
   // 调用有参方法
   methodC.invoke(testObj2, "parameter2");
  } catch (NoSuchMethodException e) {
   System.out.println( "/n **** 出错啦 ****" );
   System.out
     .println(" 此处报错,说明Method无法调用Constructor。换句话说,Method类可以调用类方法但不能调用构造器。");
   System.out.println(" 有时构造器被我们称为构造方法,但由此看来,这种说法不严格。");
  }
 }
}

<think> 我们正在讨论的是如何在Java中创建测试。根据之前的对话,用户已经了解了在Spring Boot项目中测试Service层方法的几种方式(集成测试单元测试),现在用户的问题更基础:如何创建测试本身,不局限于Spring环境。 结合引用: - 引用[1]提到了测试抽象的方法:可以通过创建具体子测试抽象,或者使用Mock框架。 - 引用[2]提到了创建Car在其main方法中测试,但单元测试通常不用main方法,而是用JUnit。 - 引用[3]提到了JUnit测试的写法以及注解。 因此,我们重点介绍使用JUnit创建测试的方法。 ### 创建测试的基本步骤 #### 1. 添加JUnit依赖 对于Maven项目,在`pom.xml`中添加: ```xml <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.8.2</version> <!-- 使用最新稳定版本 --> <scope>test</scope> </dependency> ``` #### 2. 创建测试 - 测试通常放在`src/test/java`目录下,与`src/main/java`中的对应。 - 测试的命名:通常为`被测试名 + Test`,例如`CalculatorTest`。 #### 3. 编写测试方法 - 使用`@Test`注解标记测试方法。 - 测试方法应为`void`型,并且不带参数。 示例:测试一个简单的`Calculator` ```java // 被测试 public class Calculator { public int add(int a, int b) { return a + b; } } ``` ```java // 测试 import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class CalculatorTest { @Test public void testAdd() { Calculator calculator = new Calculator(); int result = calculator.add(2, 3); assertEquals(5, result); // 断言期望值为5,实际结果为result } } ``` #### 4. 常用断言方法 - `assertEquals(expected, actual)`: 验证实际值等于期望值 - `assertTrue(condition)`: 验证条件为真 - `assertFalse(condition)`: 验证条件为假 - `assertNull(object)`: 验证对象为null - `assertNotNull(object)`: 验证对象不为null - `assertThrows(异常, executable)`: 验证执行代码段抛出指定异常 #### 5. 测试生命周期注解(JUnit5) - `@BeforeEach`: 每个测试方法运行前执行 - `@AfterEach`: 每个测试方法运行后执行 - `@BeforeAll`: 所有测试方法运行前执行(静态方法) - `@AfterAll`: 所有测试方法运行后执行(静态方法) 示例: ```java import org.junit.jupiter.api.*; public class LifecycleTest { @BeforeAll static void setupAll() { System.out.println("Before all tests"); } @BeforeEach void setup() { System.out.println("Before each test"); } @Test void testOne() { System.out.println("Test one"); } @Test void testTwo() { System.out.println("Test two"); } @AfterEach void tearDown() { System.out.println("After each test"); } @AfterAll static void tearDownAll() { System.out.println("After all tests"); } } ``` #### 6. 测试抽象(参考引用[1]) - 方法1:创建匿名内部实现抽象 ```java public abstract class AbstractClass { public abstract int abstractMethod(); public int concreteMethod() { return 42; } } public class AbstractClassTest { @Test public void testConcreteMethod() { AbstractClass instance = new AbstractClass() { @Override public int abstractMethod() { return 0; } }; assertEquals(42, instance.concreteMethod()); } } ``` - 方法2:创建专用的测试 ```java class TestConcreteClass extends AbstractClass { @Override public int abstractMethod() { return 1; } } @Test public void testConcreteMethod() { TestConcreteClass instance = new TestConcreteClass(); assertEquals(42, instance.concreteMethod()); } ``` #### 7. 测试静态方法块(参考引用[2]) 静态代码块的测试通常通过测试的初始化效果来间接完成。 ```java public class Car { static { System.out.println("Static block"); } public Car() { System.out.println("Constructor"); } } @Test public void testStaticBlock() { // 静态块在加载时执行,因此创建第一个实例时会输出 System.out.println("First instance:"); new Car(); System.out.println("Second instance:"); new Car(); } ``` #### 8. 忽略测试预期异常 ```java @Test @Disabled("暂时忽略") void skippedTest() { // 此测试不会运行 } @Test void testException() { Exception exception = assertThrows(IllegalArgumentException.class, () -> { throw new IllegalArgumentException("错误信息"); }); assertEquals("错误信息", exception.getMessage()); } ``` ### 总结 Java测试创建要点: 1. 使用JUnit框架,通过`@Test`注解定义测试方法 2. 使用断言验证结果 3. 利用生命周期方法进行初始化清理 4. 测试抽象通过具体子实现 5. 静态方法/块通过行为间接测试 > 单元测试是保证代码质量的重要手段,推荐测试覆盖率不低于70%[^1]。 §§相关问题§§ 1. 如何使用JUnit测试异常情况? 2. JUnit5与JUnit4的主要区别是什么? 3. 如何使用Mockito模拟依赖进行测试? 4. 如何测试Java中的静态方法? </think> ### Java中创建测试的方法详解 在Java中创建测试主要使用 **JUnit** 框架(当前主流为JUnit 5)。以下是具体步骤最佳实践: --- #### 1. **基础测试创建(无框架依赖)** ```java // 被测:Calculator.java public class Calculator { public int add(int a, int b) { return a + b; } } // 测试:CalculatorTest.java public class CalculatorTest { public static void main(String[] args) { Calculator calc = new Calculator(); int result = calc.add(2, 3); if (result == 5) { System.out.println("✅ 测试通过"); } else { System.out.println("❌ 测试失败"); } } } ``` **缺点**:需手动编写断言逻辑,无法自动管理测试生命周期[^2]。 --- #### 2. **使用JUnit 5(推荐)** ```java import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; // 测试 class CalculatorTest { @Test // 标记测试方法 void testAdd() { // 1. 准备测试数据 Calculator calc = new Calculator(); // 2. 执行被测方法 int result = calc.add(2, 3); // 3. 断言验证结果 assertEquals(5, result); // 预期值 vs 实际值 } } ``` **关键注解**: - `@Test`:标识测试方法 - `@BeforeEach`:每个测试前执行(初始化) - `@AfterEach`:每个测试后执行(清理) - `@DisplayName`:自定义测试名称 --- #### 3. **测试抽象(参考引用[1])** ```java // 抽象 AbstractService.java public abstract class AbstractService { public abstract String process(String input); public String commonMethod() { return "BASE"; } } // 测试 AbstractServiceTest.java class AbstractServiceTest { // 创建匿名实现进行测试 @Test void testCommonMethod() { AbstractService service = new AbstractService() { @Override public String process(String input) { return input.toUpperCase(); } }; assertEquals("BASE", service.commonMethod()); } } ``` **要点**:通过匿名子实例化抽象测试具体方法逻辑[^1]。 --- #### 4. **进阶场景** **异常测试**: ```java @Test void testDivisionByZero() { Calculator calc = new Calculator(); Exception exception = assertThrows( ArithmeticException.class, () -> calc.divide(10, 0) // 触发异常的方法调用 ); assertTrue(exception.getMessage().contains("除数不能为零")); } ``` **参数化测试**: ```java @ParameterizedTest @ValueSource(ints = {1, 2, 3}) void testSquare(int input) { assertEquals(input * input, new Calculator().square(input)); } ``` --- #### 5. **最佳实践** 1. **命名规范**: - 测试:`被测名 + Test`(如`UserServiceTest`) - 测试方法:`方法名_场景_预期`(如`transfer_insufficientBalance_throwsException`) 2. **测试隔离**:每个测试方法独立运行,互不影响 3. **FIRST原则**: - **F**ast(快速) - **I**ndependent(独立) - **R**epeatable(可重复) - **S**elf-validating(自验证) - **T**imely(及时) > 提示:使用`@SuppressWarnings`抑制无关警告(如序列化警告)[^3] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值