Mock技巧

1. @Mock 注解

  • 作用@Mock 注解用于创建一个模拟对象(Mock 对象)。模拟对象是一个完全虚拟的对象,它不会执行真实对象的任何方法逻辑,而是根据测试的需要返回预设的值或者执行预设的行为。
  • 使用场景:当你想要隔离被测试对象与外部依赖,控制外部依赖的行为时,可以使用 @Mock 注解。
  • 示例代码
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.when;

// 使用 MockitoExtension 扩展来启用 Mockito 注解
@ExtendWith(MockitoExtension.class)
public class MockExample {

    // 创建一个 Mock 对象
    @Mock
    private MyService myService;

    @Test
    public void testMock() {
        // 预设 Mock 对象的方法行为
        when(myService.doSomething()).thenReturn("Mocked result");

        // 调用 Mock 对象的方法
        String result = myService.doSomething();

        // 验证结果
        System.out.println(result); // 输出: Mocked result
    }
}

class MyService {
    public String doSomething() {
        return "Real result";
    }
}

在上述代码中,myService 是一个 Mock 对象,当调用 doSomething() 方法时,它会返回预设的 "Mocked result",而不是真实的 "Real result"

2. @Spy 注解

  • 作用@Spy 注解用于创建一个真实对象的包装器(Spy 对象)。Spy 对象会调用真实对象的方法,除非你明确地对某些方法进行了 stub(预设)。
  • 使用场景:当你想要测试一个对象的大部分真实行为,但又需要控制某些方法的返回值时,可以使用 @Spy 注解。
  • 示例代码
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.List;

import static org.mockito.Mockito.doReturn;

// 使用 MockitoExtension 扩展来启用 Mockito 注解
@ExtendWith(MockitoExtension.class)
public class SpyExample {

    // 创建一个 Spy 对象
    @Spy
    private List<String> spyList = new ArrayList<>();

    @Test
    public void testSpy() {
        // 预设 Spy 对象的方法行为
        doReturn("Mocked element").when(spyList).get(0);

        // 调用 Spy 对象的方法
        spyList.add("Real element");
        String result = spyList.get(0);

        // 验证结果
        System.out.println(result); // 输出: Mocked element
    }
}

在上述代码中,spyList 是一个 Spy 对象,当调用 add() 方法时,它会执行真实的添加操作;而当调用 get(0) 方法时,它会返回预设的 "Mocked element"

3. @InjectMocks 注解

  • 作用@InjectMocks 注解用于创建一个真实对象,并将使用 @Mock 或 @Spy 注解创建的模拟对象或 Spy 对象注入到该真实对象的依赖中。
  • 使用场景:当你想要测试一个对象的真实行为,同时又需要隔离其外部依赖时,可以使用 @InjectMocks 注解。
  • 示例代码
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.when;

// 使用 MockitoExtension 扩展来启用 Mockito 注解
@ExtendWith(MockitoExtension.class)
public class InjectMocksExample {

    // 创建一个 Mock 对象
    @Mock
    private MyService myService;

    // 创建一个真实对象,并注入 Mock 对象
    @InjectMocks
    private MyClass myClass;

    @Test
    public void testInjectMocks() {
        // 预设 Mock 对象的方法行为
        when(myService.doSomething()).thenReturn("Mocked result");

        // 调用真实对象的方法
        String result = myClass.callService();

        // 验证结果
        System.out.println(result); // 输出: Mocked result
    }
}

class MyClass {
    private MyService myService;

    public MyClass(MyService myService) {
        this.myService = myService;
    }

    public String callService() {
        return myService.doSomething();
    }
}

class MyService {
    public String doSomething() {
        return "Real result";
    }
}

在上述代码中,myClass 是一个真实对象,myService 是一个 Mock 对象,通过 @InjectMocks 注解将 myService 注入到 myClass 中。当调用 myClass.callService() 方法时,会调用 myService 的 doSomething() 方法,返回预设的 "Mocked result"

总结

  • @Mock:创建一个完全虚拟的对象,不执行真实方法逻辑。
  • @Spy:创建一个真实对象的包装器,默认执行真实方法逻辑,可对部分方法进行 stub。
  • @InjectMocks:创建一个真实对象,并将 Mock 对象或 Spy 对象注入到该真实对象的依赖中

技巧一:当使用jpa或者mybatis自动注入mapper时

先mock一个mapper,
由于injectMock的是userServiceImpl对象,而使用的mapper是从他的父类ServiceImpl里面拿的,所以mapper不能注入到父属性【由于getBaseMapper方法返回的baseMapper是父类】;所以可以在userServiceImpl调用到getMapper时,打桩到userServiceImpl里面
Open: Pasted image 20250219004700.png
9f8e50b47f2494f358e3a1f733a34ee1_MD5.jpeg
getByID实际是调用的Iservice.getByID()=>mapper又是走的父类ServiceImpl的
Open: Pasted image 20250219004812.png
c508cec9ba7581684994195915f1d295_MD5.jpeg
父类:ServiceImpl
Open: Pasted image 20250219005522.png
2026e45bc23d88d797d49220c75e34d3_MD5.jpeg
Open: Pasted image 20250219004853.png
820680432fde166192a7a16cd0e2d4d2_MD5.jpeg