Main Content

验证 Mock 对象交互

当您创建 mock 时,还会创建一个用于控制 mock 行为的关联行为对象。使用此对象可访问所拦截的从受测组件发送到 mock 对象的消息(称为 spying 的进程)。有关创建 mock 的详细信息,请参阅创建 Mock 对象

在模拟框架中,验证为用于测试与该对象的交互的函数。有四种验证类型:

  • 确认 - 在不引发异常的情况下产生并记录失败。由于确认不会引发异常,因此即使出现确认失败的情形,依然会完成所有的测试内容。通常,确认是单元测试的主要验证类型,因为这些确认一般不要求提前从测试中退出。使用其他验证类型来测试是否违反先决条件或测试安装是否正确。

  • 假设 - 确保测试环境满足先决条件,不会导致测试失败。假设失败会导致测试被滤除,且测试框架会将这些测试标记为未完成。

  • 断言 - 确保失败情况会使当前测试内容的剩余部分失效,但不会阻止后续测试方法正常执行。断言点处的失败会将当前测试方法标记为失败且未完成。

  • 致命断言 - 在失败时中止测试会话。当失败涉及根本以致没必要继续测试时,这种验证会很有用。当脚手架拆解未能正确还原 MATLAB® 状态,适合中止测试并启动一个新会话时,这些验证也很有用。

mock 对象是超类所指定接口的抽象方法和属性的实现。您也可以在没有超类的情况下构造 mock,在这种情况下,mock 具有一个隐式接口。为骰子类创建一个具有隐式接口的 mock。该接口包含 ColorNumSides 属性以及 roll 方法,后者接受骰子数并返回一个值。虽然该接口当前未实现,但您可以创建一个具有该接口的 mock。

testCase = matlab.mock.TestCase.forInteractiveUse;
[mock,behaviorObj] = testCase.createMock('AddedProperties', ...
    {'NumSides','Color'},'AddedMethods',{'roll'});

验证 Mock 方法交互

由于 mock 会记录向其发送的交互,因此您可以验证是否调用了 mock 方法。掷一个骰子。

val = mock.roll(1);

验证是否使用了 1 个骰子调用 roll 方法。

testCase.verifyCalled(behaviorObj.roll(1))
Interactive verification passed.

验证是否使用了 3 个骰子调用 roll 方法。此测试将失败。

testCase.verifyCalled(behaviorObj.roll(3), ...
    'roll method should have been called with input 3.')
Interactive verification failed.

----------------
Test Diagnostic:
----------------
roll method should have been called with input 3.

---------------------
Framework Diagnostic:
---------------------
verifyCalled failed.
--> Method 'roll' was not called with the specified signature.
--> Observed method call(s) with any signature:
        out = roll([1×1 matlab.mock.classes.Mock], 1)

Specified method call:
    MethodCallBehavior
        [...] = roll(<Mock>, 3)

验证是否未使用 2 个骰子调用 roll 方法。

testCase.verifyNotCalled(behaviorObj.roll(2))
Interactive verification passed.

由于 MethodCallBehavior 类的 withAnyInputswithExactInputswithNargout 方法会返回 MethodCallBehavior 对象,因此您可以在验证中使用这些方法。验证是否使用了任何输入至少调用一次 roll 方法。

testCase.verifyCalled(withAnyInputs(behaviorObj.roll))
Interactive verification passed.

验证是否未使用 2 个输出和任何输入调用 roll 方法。

testCase.verifyNotCalled(withNargout(2,withAnyInputs(behaviorObj.roll)))
Interactive verification passed.

验证 Mock 属性交互

与方法调用类似,mock 会记录属性设置和访问操作。设置骰子的颜色。

mock.Color = "red"
mock = 

  Mock with properties:

    NumSides: []
       Color: "red"

验证是否设置了颜色。

testCase.verifySet(behaviorObj.Color)
Interactive verification passed.

验证是否对颜色进行了访问。此测试将通过,因为在 MATLAB 显示该对象时会隐式访问属性。

testCase.verifyAccessed(behaviorObj.Color)
Interactive verification passed.

断言未设置面数。

testCase.assertNotSet(behaviorObj.NumSides)
Interactive assertion passed.

使用 Mock 对象约束

matlab.mock.TestCase 方法便于监视 mock 交互。但是,如果您改用 matlab.mock.constraints 包中的类,则有更多功能可供使用。要使用约束,请将行为对象和约束传递给 verifyThatassumeThatassertThatfatalAssertThat 方法。

创建一个新的 mock 对象。

testCase = matlab.mock.TestCase.forInteractiveUse;
[mock,behaviorObj] = testCase.createMock('AddedProperties', ...
    {'NumSides','Color'},'AddedMethods',{'roll'});

掷 2 个骰子。然后,通过约束来验证是否使用了两个骰子至少调用一次 roll 方法。

val = mock.roll(2);

import matlab.mock.constraints.WasCalled
testCase.verifyThat(behaviorObj.roll(2),WasCalled)
Interactive verification passed.

掷一个骰子。然后,验证是否使用了任何输入至少调用两次 roll 方法。

val = mock.roll(1);

testCase.verifyThat(withAnyInputs(behaviorObj.roll), ...
    WasCalled('WithCount',2))
Interactive verification passed.

验证是否未访问 NumSides

import matlab.mock.constraints.WasAccessed
testCase.verifyThat(behaviorObj.NumSides,~WasAccessed)
Interactive verification passed.

设置骰子的颜色。然后,验证是否将该属性设置了一次。

mock.Color = "blue";

import matlab.mock.constraints.WasSet
testCase.verifyThat(behaviorObj.Color,WasSet('WithCount',1))
Interactive verification passed.

访问 Color 属性。然后,验证该属性是否未正好访问一次。此测试将失败。

c = mock.Color

testCase.verifyThat(behaviorObj.Color,~WasAccessed('WithCount',1))
c = 

    "blue"

Interactive verification failed.

---------------------
Framework Diagnostic:
---------------------
Negated WasAccessed failed.
--> Property 'Color' was accessed the prohibited number of times.
    
    Actual property access count:
             1
    Prohibited property access count:
             1

Specified property access:
    PropertyGetBehavior
        <Mock>.Color

设置面数。然后,验证面数是否设置为 22。

mock.NumSides = 22;
testCase.verifyThat(behaviorObj.NumSides,WasSet('ToValue',22))
Interactive verification passed.

使用 matlab.unittest.constraints 包中的约束来断言骰子的面数未被设置为超过 20。此测试将失败。

import matlab.unittest.constraints.IsLessThanOrEqualTo
testCase.verifyThat(behaviorObj.NumSides, ...
    WasSet('ToValue',IsLessThanOrEqualTo(20)))
Interactive verification failed.

---------------------
Framework Diagnostic:
---------------------
WasSet failed.
--> Property 'NumSides' was not set to the specified value.
--> Observed property set(s) to any value:
        <Mock>.NumSides = 22

Specified property set:
    PropertySetBehavior
        <Mock>.NumSides = <IsLessThanOrEqualTo constraint>

验证概述

验证类型TestCase 方法matlab.mock.constraints
使用 matlab.unittest.TestCase 方法通过 matlab.mock.constraints
已调用方法verifyCalledverifyNotCalledverifyThatWasCalledOccurred
assumeCalledassumeNotCalledassumeThat
assertCalledassertNotCalledassertThat
fatalAssertCalledfatalAssertNotCalledfatalAssertThat
方法已被调用特定次数不适用verifyThatassumeThatassertThatfatalAssertThatWasCalled
已访问属性verifyAccessedverifyNotAccessedverifyThatWasAccessedOccurred
assumeAccessedassumeNotAccessedassumeThat
assertAccessedassertNotAccessedassertThat
fatalAssertAccessedfatalAssertNotAccessedfatalAssertThat
属性已被访问特定次数不适用verifyThatassumeThatassertThatfatalAssertThatWasAccessed
已设置属性verifySetverifyNotSetverifyThatWasSetOccurred
assumeSetassumeNotSetassumeThat
assertSetassertNotSetassertThat
fatalAssertSetfatalAssertNotSetfatalAssertThat
属性已被设置特定次数不适用verifyThatassumeThatassertThatfatalAssertThatWasSet
属性已被设置为特定值不适用verifyThatassumeThatassertThatfatalAssertThatWasSetOccurred
按特定顺序调用方法并访问或设置属性不适用verifyThatassumeThatassertThatfatalAssertThatOccurred