将抽象常量属性分配给模拟

时间:2017-10-10 16:13:21

标签: matlab unit-testing mocking

我正在开发一个具有以下类的层次结构的项目:

images.example.com
example-bucket.s3-website-us-west-1.amazonaws.com
% Standard class that has properties and methods shared by all classes in the project
classdef StandardClass < handle
    properties (Constant, Abstract)
        displayName
    end
end

使用这个MWE,我可以创建具体类的实例,我可以查询displayName。

现在,我想测试与我的% Abstract class that defines the interface for a particular set of concrete classes classdef AbstractClass < StandardClass methods function name = getDisplayName(obj) name = obj.displayName; end end end 接口的另一个类。我不想编写循环遍历每个具体类并测试界面的测试,而是想使用新的模拟框架使用我的% Actual implementation of the concrete class classdef ConcreteClass < AbstractClass properties (Constant) displayName = 'My Concrete Class' end end 作为模板进行模拟:

AbstractClass

以错误结束:

AbstractClass
嗯,那真是太糟糕了。不过我想我明白了。模拟器无法知道如何分配抽象属性,所以我添加:

classdef UnitTest < matlab.mock.TestCase
    methods (Test)
        function testDisplay(obj)
            concrete = createMock(obj, ?AbstractClass);

            % My test here
        end
    end
end

到我的--------- Error ID: --------- 'MATLAB:mock:MockContext:NonDefaultPropertyAttribute' -------------- Error Details: -------------- Error using matlab.mock.internal.MockContext>validateAbstractProperties (line 623) Unable to create a mock for the 'AbstractClass' class because Abstract property 'displayName' has a non-default value for its 'Constant' attribute. 。然后当我运行我的测试时,我的模拟器被创建并且单元测试运行良好。但是,如果我然后去尝试在测试框架之外创建具体类:

properties (Constant)
    displayName = 'Abstract Class';
end

所以我陷入了困境22。我可以让模拟工作并成功运行单元测试,只有当我打破代码使它不能运行时。

我正在使用的代码库有很多基于我​​们标准类的抽象类。有没有办法告诉模拟框架在使用模板调用AbstractClass时如何分配>> test = ConcreteClass(); Error using ConcreteClass Cannot define property 'displayName' in class 'ConcreteClass' because the property has already been defined in the superclass 'AbstractClass'. 属性?

1 个答案:

答案 0 :(得分:2)

编辑:从MATLAB R2018a开始,可以使用'DefaultPropertyValues'名称/值对和createMock方法。

例如:

classdef UnitTest < matlab.mock.TestCase
    methods (Test)
        function testDisplay(testCase)
            concrete = createMock(testCase, ?AbstractClass, ...
                'DefaultPropertyValues',struct('displayName','Abstract Class'));

            % My test here
        end
    end
end

有关详细信息,请参阅相关文档页面: https://www.mathworks.com/help/matlab/ref/matlab.mock.testcase.createmock.html?searchHighlight=DefaultPropertyValues

先前版本的原始答案

正如您所发现的,没有办法为具有Abstract,Constant属性的类创建模拟,但这是我们将在未来版本中考虑的功能。

这是一种解决方法:

从MATLAB R2017b开始,您可以使用Abstract,Static方法为类创建模拟: https://www.mathworks.com/help/matlab/release-notes.html?searchHighlight=Mocking%20Framework%3A&s_tid=doc_srchtitle

因此,您可以重新构造代码以使用Static方法而不是Constant属性:

% Standard class that has properties and methods shared by all classes in the project
classdef StandardClass < handle
    methods (Abstract, Hidden, Static)
        name = getDisplayNameInternal
    end
end


% Abstract class that defines the interface for a particular set of concrete classes
classdef AbstractClass < StandardClass
    methods
        function name = getDisplayName(obj)
            name = obj.getDisplayNameInternal;
        end
    end
end

% Actual implementation of the concrete class
classdef ConcreteClass < AbstractClass
    methods (Hidden, Static)
        function name = getDisplayNameInternal
            name = 'My Concrete Class';
        end
    end
end

然后您可以创建一个模拟:

[concrete, behavior] = createMock(obj, ?AbstractClass);
assignOutputsWhen(obj, withAnyInputs(behavior.getDisplayNameInternal), 'My mock class');

实现了所需的行为:

>> concrete.getDisplayName
ans =
    'My mock class'