前言

框架

用途和特点

缺点

JUnit

JUnit 是 Java 的单元测试框架,用于编写和执行测试用例

不直接支持模拟对象(Mocking),需要结合 Mockito 或其他 Mock 框架使用

Mockito

Mockito 是一个 Java Mock 框架,用于在单元测试中创建模拟对象

  • 简单易用,API 设计直观。

  • 功能强大,可以模拟大多数对象。

  • 语法优美,提高了代码的可读性。

不支持模拟静态方法、私有方法和 final 类

PowerMockito

PowerMockito 是 Mockito 的扩展,提供了对 Mockito 无法模拟的类的模拟能力

  • 支持模拟静态方法、私有方法、构造函数和 final 类/方法。

  • 可以与 Mockito 和 Spock 集成使用。

学习曲线较陡峭

Spock

Spock 是基于 Groovy 的测试框架,适用于 Java 和 Groovy 应用的测试

  • 遵循 BDD 模式,提供更灵活的测试行为控制。

  • 用自然语言描述测试步骤,易于理解和维护。

  • 兼容 Mock 框架,降低迁移成本。

  • Groovy 语言的动态特性使得 Spock 的语法简洁

  • Spock 允许使用 Mockito 的Mock功能,并且从 Spock 2.x 版本开始,也支持与 PowerMock 集成,从而扩展了模拟能力。

  • 学习成本相对较高,特别是对于不熟悉 Groovy 的开发者。

Junit和Spock是测试框架,其关系就是LogBack与Log4fj的区别。

Mockito和PowerMockito是Mock框架,其不是测试框架,其需要结合Junit或Spock使用

一、简单场景

class SimpleTest extends spock.lang.Specification {
    def "测试加法运算"() {
        given:
        int num1 = 5
        int num2 = 3


        when:
        int result = num1 + num2


        then:
        result == 8
    }
}

二、Where 中添加多用例的场景

class WhereTest extends spock.lang.Specification {
    def "测试乘法运算结果"() {
        expect:
        num1 * num2 == expectedResult


        where:
        num1 | num2 | expectedResult
        2    | 3    | 6
        4    | 5    | 20
        6    | 7    | 42
    }
}

三、参数引用参数场景

class ParameterReferenceTest extends spock.lang.Specification {
 def "测试加法运算,结果与输入参数相关"() {
        expect:
        num1 + num2 == expectedSum


        where:
        num1 | num2 | expectedSum
        5    | 3    | num1 + num2
        10   | 20   | num1 + num2
        15   | 5    | num1 + num2
    }
}

四、Shared 对象场景

class SharedObjectTest extends spock.lang.Specification {
    @Shared
    def sharedObject = new SharedObject()


    def "测试共享对象的属性"() {
        given:
        sharedObject.setValue(5)


        when:
        def retrievedValue = sharedObject.getValue()


        then:
        retrievedValue == 5
    }
}

五、Mock Final 类

import spock.mock.DetachedMockFactory
@RunWith(PowerMockRunner.class) // 必须
@PowerMockRunnerDelegate(Sputnik.class)
@PrepareForTest(FinalClass.class) // (1)必须将Final类WalletCoinDao添加到这里
class MockFinalClassTest extends spock.lang.Specification {
    @Mock
    FinalClass finalClass
    @InjectMocks
    ClassUnderTest classUnderTest


    def "测试 Mock Final 类"() {
        given:
        when(finalClass.someMethod()).thenReturn("hello")
        when:
        def result = classUnderTest.invokeFinalClassMethod()
        then:
        result == "hello"
    }
    }
}


final class FinalClass {
   public  String someMethod() {
       return  "Original Result";
    }
}
@Service
class ClassUnderTest {


    @Autowired
    private FinalClass finalClass;


    public String invokeFinalClassMethod() {
        return finalClass.someMethod();
    }
}

六、Mock Final 方法

import spock.lang.Unroll
@RunWith(PowerMockRunner.class)
// 必须
@PowerMockRunnerDelegate(Sputnik.class)
@PrepareForTest([FinalClassMethod.class])


class MockFinalMethodTest extends spock.lang.Specification {
      def "测试 Mock Final method "() {
        given:
        def finalClassMethod = PowerMockito.spy(new FinalClassMethod())
        PowerMockito.doReturn("hello1").when(finalClassMethod).someMethodV2()
        when:
        def result = finalClassMethod.someMethodV2()
        then:
        result == "hello1"
    }
}


class SomeClass {
    final String finalMethod(int num) {
        "Original Result"
    }
}

七、Mock Static 方法

import spock.lang.Specification
import spock.mock.SharedMockFixture
import static org.mockito.Mockito.mockStatic
@RunWith(PowerMockRunner.class)
// 必须
@PowerMockRunnerDelegate(Sputnik.class)
@PrepareForTest([StaticClass.class])
class MockStaticMethodTest extends Specification implements SharedMockFixture {


    def "测试 Mock Static 方法"() {
        given:
        PowerMockito.mockStatic(StaticClass.class)
        
        when:
        PowerMockito.when(StaticClass.staticMethod()).thenReturn("Expected Result")
        
        then:
        new ClassUnderTest().invokeStaticMethod2() == "Expected Result"


    }
}


class StaticClass {
    static String staticMethod() {
      return  "Original Static Result";
    }
}

八、Mock 私有变量

import spock.lang.Specification
import org.spockframework.util.InternalSpockError


class MockPrivateVariableTest extends Specification {
    def "测试 Mock 私有变量"() {
        given:
        def target = new TargetClass()
        def field = TargetClass.getDeclaredField("privateVariable")
        field.setAccessible(true)
        field.set(target, "Mocked Value")


        when:
        def result = target.accessPrivateVariable()


        then:
        result == "Expected Result"
    }
}


class TargetClass {
    private String privateVariable = "Original Value"


    String accessPrivateVariable() {
        privateVariable
    }
}

九、Mock 无返回值的函数

import spock.lang.Specification


class MockVoidMethodTest extends Specification {
    def "测试 Mock 无返回值的函数"() {
        //given
        doNothing().when(myclass).doSayHello(Mockito.anyString());
        //when
        String result = myclass.sayHello("hello");
        //then
        assertEquals("ok", result);
    }
}


class SomeObject {
    void voidMethod() {
        // 原始实现
    }
}

十、Mock 抛异常

import spock.lang.Specification


class MockExceptionTest extends Specification {
    def "测试 Mock 抛异常"() {
        //given
        doThrow(new RuntimeException("my exception")).when(myclass).doSayHello(Mockito.anyString());
        //when
        String result = myclass.sayHello("hello");
        //then
        assertEquals("ok", result);
    }
}


class SomeObject {
    void methodThatThrows() {
        // 原始实现
    }
}

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部