【Java】单元测试是什么?

单元测试

  • 1、单元测试是什么?步骤
  • 2、简单的单元操作,Demo
  • 3、什么是打桩
    • 打桩的主要优点是:

1、单元测试是什么?步骤

单元测试(Unit Testing)是软件开发中的一种测试方法,用于确保单个代码单元(如函数或方法)按照预期运行。通过编写单元测试,开发人员可以检查每个代码单元是否能够独立地产生正确的结果。单元测试有助于识别和修复代码中的错误,从而提高软件质量。
通常,一个单元测试的步骤如下:

  1. 编写测试用例:针对代码单元编写一组测试用例,每个测试用例包含特定的输入和预期输出。
  2. 运行测试:使用测试框架运行编写的单元测试,测试框架通常可以自动执行所有测试用例并报告结果。
  3. 检查结果:测试框架会报告每个测试用例的通过或失败状态。如果某个测试用例失败了,这意味着代码单元存在问题,需要进行调试和修复。
  4. 修复代码:针对失败的测试用例,开发人员需要调查错误原因,并修改相应的代码,以使测试通过。
  5. 重复运行测试:在修复代码后,再次运行所有测试用例,确保修复后的代码没有引入新的错误。
  6. 单元测试的主要目的是确保代码的可靠性、稳定性和可维护性。通过编写和执行单元测试,开发人员可以在项目的早期阶段发现和修复错误,从而避免了在项目后期出现难以排查的问题。

2、简单的单元操作,Demo

Spring Boot中实现单元测试,步骤如下:

  1. 添加依赖:
    pom.xml
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
  1. 编写测试类:创建一个要测试的类相对应的测试类。测试类应位于与要测试的类相同的包中,并遵循命名约定,例如YourClassTest。在测试类中,使用@RunWith(SpringRunner.class) 注解来指定测试运行器,并使用 @SpringBootTest注解来启用Spring Boot测试功能。
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class YourClassTest {
    // 编写测试用例
}
  1. 编写测试用例:在测试类中,为要测试的每个方法编写一个或多个测试用例。使用JUnit的@Test注解来标记测试方法。可以使用断言(如assertEqualsassertTrue等)来验证方法的输出是否符合预期。
import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class YourClassTest {
    @Test
    public void testYourMethod() {
        YourClass yourClass = new YourClass();
        int expectedResult = 42;
        int actualResult = yourClass.yourMethod();
        assertEquals(expectedResult, actualResult);
    }
}
  1. 运行测试,如果有测试用例失败,就修改对应的实现代码,并重新运行测试,直到所有测试用例均通过。

再补充一个例子:
例如HelloController,测试 /hello,编写测试类:

@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class HelloControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ServletContext servletContext;

    @Test
    public void test1() throws Exception{
        MvcResult end = mockMvc.perform(requestBuilder("/hello"))
                .andExpect(mvcResult -> {
                    if (mvcResult.getResponse().getStatus() != 200) {
                        throw new RuntimeException("failed.");
                    }
                })
                .andExpect(result -> {
                    if (!result.getResponse().getContentType().contains("json")) {
                        throw new RuntimeException("failed");
                    }
                }).andReturn();

        System.out.println(end);
    }

    private RequestBuilder requestBuilder(String uri) {
        return MockMvcRequestBuilders.get(URI.create(uri)).accept(MediaType.APPLICATION_JSON_UTF8)
                .characterEncoding("UTF-8");
    }
}

补充:实际项目你可能会遇到一些耦合性很强的业务方法,这个时候你就痛苦了。比如:输入参数过多,参数存在较多的等价类,这些都是设计时就要避免的。
解决办法:
1.使用全局变量/对象属性进行输出, 尽量减少函数的相互调用。
2.分离模块的I/O操作,减少函数调用。
3.对函数调用进行封装,测试时不进行调用,而是通过全局变量输出函数ID和参数。
4.对通过函数调用获取输入的情况,同样封装为函数ID和全局变量的输入。

3、什么是打桩

单元测试中的打桩(Stubbing)是一种测试技术,用于在测试过程中替换实际组件(如方法、对象或服务)的行为。打桩通常用于模拟代码中的某些部分,以便在测试中控制它们的行为。这样就可以专注于测试目标方法或类,而无需担心外部依赖或其他组件的影响。

打桩的主要优点是:

  1. 隔离:通过使用打桩隔离要测试的代码单元,使其不受外部依赖或其他组件的干扰。这样可以确保单元测试只关注目标代码的功能,而不是整个系统的行为。
  2. 可控:打桩允许预先定义替换组件的行为。这意味着可以在测试中精确地控制这些组件的输出,从而更容易地测试不同的场景和边界条件。
  3. 简化:有时,实际组件可能很复杂或难以设置。通过使用打桩,可以替换这些组件为简单的、易于管理的模拟对象,从而简化测试过程。

要在单元测试中实现打桩,可以使用一些模拟框架,比如Mockito等。
以下是一个使用Mockito进行打桩的简单示例:

import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

public class YourClassTest {
    @Test
    public void testYourMethodWithStub() {
        // 创建一个依赖类的模拟对象
        DependencyClass mockDependency = Mockito.mock(DependencyClass.class);

        // 为模拟对象的某个方法设置预期行为(打桩)
        when(mockDependency.someMethod()).thenReturn("stubbedValue");

        // 将模拟对象传递给要测试的类
        YourClass yourClass = new YourClass(mockDependency);

        // 调用要测试的方法
        String expectedResult = "expectedResult";
        String actualResult = yourClass.yourMethod();

        // 验证结果
        assertEquals(expectedResult, actualResult);
    }
}

在这个示例中,我们使用MockitoDependencyClass创建了一个模拟对象,并为其someMethod方法设置了预期行为。然后,我们将模拟对象传递给 YourClass,并执行测试。
通过这种方式,我们可以确保测试仅关注 YourClass的行为,而不受DependencyClass的实际实现的影响。

如有错误,还请多多指教!
转载或者引用本文内容请注明来源及原作者:橘足轻重;

你可能感兴趣的:(项目开发,SpringBoot,测试,单元测试,java,junit)