【问题标题】:nsubstitute property getter override does not worknsubstitute 属性 getter 覆盖不起作用
【发布时间】:2014-07-01 13:08:34
【问题描述】:

我是使用 nsubstitute 进行测试的新手。所以也许这对你来说是一个微不足道的问题。但我找不到一个。我请你帮我解决以下问题。

我在测试一个抽象类时遇到了问题:

public abstract class BaseClass
{
    public string Name
    {
        get { return GetName(); }
        set { SetName(value); }
    }

    protected abstract string GetName();

    protected abstract void SetName(string value);

}

我想测试一下,getter 和 setter 是否在抽象类中被正确调用。要获取我派生的类的受保护抽象方法:

public class MockClass:BaseClass
{
    protected override string GetName()
    {
        return MockGetName();
    }

    protected override void SetName(string value)
    {
        MockSetName(value);
    }

    public virtual string MockGetName()
    {
        return string.Empty;
    }

    public virtual void MockSetName(string value)
    {
    }
}

现在我想测试一下,如果调用了 MockGetName()-Method,当通过以下方式获取 Name-Property 的值时:

public void TestNameGetter()
{
    // arrange
    MockClass mock = Substitute.For<MockClass>();
    mock.MockGetName().Returns(" Irgendein Name ");

    // act
    string name = mock.Name;

    // assert
    Assert.AreEqual(" Irgendein Name ", name, "Wrong name");
    mock.DidNotReceive().MockSetName(Arg.Any<string>());
    mock.Received().MockGetName();
}

但从未调用过 MockGetName 方法,并且变量名的值错误。

我希望任何人都可以帮助我测试功能。谢谢

【问题讨论】:

    标签: c# nsubstitute


    【解决方案1】:

    问题在于 NSubstitute 正在拦截 MockClass.GetName 调用并返回该调用的默认值(空字符串)。所以当mock.Name 在测试中运行时,它会调用GetName 并且我们会得到空字符串,不管MockGetName 会返回什么。

    我不确定您到底想要达到什么目的,但是如果您想使用 NSubstitute 来处理这类事情,首先想到的选择是直接使用该属性,或者将 GetName 更改为上市。或者,避免使用 NSubstitute 并将测试所需的逻辑直接放入 MockClass。

    可模拟属性

        public abstract class BaseClass
        {
            public virtual string Name { get; set; }
        }
    
        [Test]
        public void TestNameGetter()
        {
            var mock = Substitute.For<BaseClass>();
            mock.Name.Returns("ABC");
    
            string name = mock.Name;
    
            Assert.AreEqual("ABC", name, "Wrong name");
        }
    

    公共访问器方法

        public abstract class BaseClass
        {
            public string Name
            {
                get { return GetName(); }
                set { SetName(value); }
            }
    
            public abstract string GetName();
            public abstract void SetName(string value);
        }
    
        [Test]
        public void TestNameGetter()
        {
            var mock = Substitute.For<BaseClass>();
            mock.GetName().Returns("ABC");
    
            string name = mock.Name;
    
            Assert.AreEqual("ABC", name, "Wrong name");
            mock.DidNotReceive().SetName(Arg.Any<string>());
            mock.Received().GetName();
        }
    

    手工编码的模拟

        public class MockClass : BaseClass
        {
            public bool GetNameWasCalled = false;
            public bool SetNameWasCalled = false;
            protected override string GetName() { GetNameWasCalled = true; return "ABC"; }
            protected override void SetName(string value) { SetNameWasCalled = true; }
        }
    
        [Test]
        public void TestNameGetter()
        {
            // arrange
            var mock = new MockClass();
    
            // act
            string name = mock.Name;
    
            // assert
            Assert.AreEqual("ABC", name, "Wrong name");
            Assert.False(mock.SetNameWasCalled);
            Assert.True(mock.GetNameWasCalled);
        }
    

    【讨论】:

    • 感谢大卫的回复。我试图测试行为,即 setter 方法被调用,当属性被设置并且 getter 方法被调用,当属性值被获取时。我认为第三种解决方案很好。第一个不测试我想要测试的内容。第二个不适合我,因为我想让 getter 和 setter 方法对外部类不可见。
    • 如果您使用自动属性,您将免费获得它! :)
    • 如果只有一个类,您的权利,但是有几个类从 Baseclass 继承,它们以不同的方式处理属性。
    • 对,那么你能测试一下调用 get/set 时每个子类会发生什么吗?不需要显式断言它们被调用,它由 C# 保证。
    猜你喜欢
    • 1970-01-01
    • 2011-01-28
    • 2018-11-08
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多