【发布时间】:2021-08-17 04:13:23
【问题描述】:
tl;dr 试图了解测试类的正确方法,但需要覆盖依赖项的某些成员。下面我描述了我尝试子类化此依赖项的思考过程,但也许我应该只重新实现依赖项的接口并跳过尝试完全覆盖和子类化依赖项?
好的,我正在尝试对依赖于调用对象的类进行单元测试。我想让该对象的属性可变,这样我就可以在测试期间更改它们,而不是让它调用网络。我认为这很棘手,因为父类在相关属性上只有一个 getter。我对 C# 有点陌生,希望能确认/纠正我目前的推理。
我有一个界面:
public interface ISettings
{
bool IsFooEnabled { get; }
}
还有一个班级
public class Settings : ISettings
{
public bool IsFooEnabled => bool.Parse(DoNetworkStuff());
}
我在测试中做了一个此类: 图一:
public class TestSettings : Settings
{
public bool IsFooEnabled = true;
}
我希望将被覆盖的对象传递给对象的构造函数,因为通常SomeObject 需要一个ISettings 对象:
public void Test()
{
TestSettings s = new TestSettings();
s.IsFooEnabled = true;
SomeObject s = new SomeObject(s);
}
所以测试失败是因为DoNetworkStuff() 正在返回null:
图 1.1:
System.ArgumentNullException : Value cannot be null. (Parameter 'value')
Stack Trace:
Boolean.Parse(String value)
Settings.get_IsFooEnabled() line 113
我认为是因为
同样的错误: 图2:
public class TestSettings : Settings
{
public bool IsFooEnabled { get; set; }
}
和 图3:
public class TestSettings : Settings
{
public bool IsFooEnabled => false;
}
和 图4:
public class TestSettings : Settings
{
public bool IsFooEnabled = false;
}
全部返回图1.1的错误。这意味着Settings.IsFooEnabled 没有被覆盖,它仍在尝试调用并获得空值。我对此感到困惑,因为我认为在子类中,子类的定义优先。但是预期的类型是Settings,所以我认为TestSettings IsFooEnabled 被忽略了。
但这有效: 图4:
public class TestSettings : Settings
{
public override bool IsFooEnabled => false;
}
但是我必须将设置更改为虚拟,否则它会抱怨,这是有道理的,因为在父类中没有虚拟就无法覆盖: 图5:
public class Settings : ISettings
{
public virtual bool IsFooEnabled => bool.Parse(DoNetworkStuff());
}
我也尝试自行覆盖该属性: 图6:
public class TestSettings : Settings
{
public override bool IsFooEnabled = false;
}
但是得到了这个错误:
Severity Code Description Project File Line Suppression State
Error CS0106 The modifier 'override' is not valid for this item Foo.Unit.Tests Foo.cs 33 N/A
这是有道理的,因为您不能覆盖属性。 我认为总的来说我有点困惑为什么属性声明不会覆盖父类的属性表达式。我认为父母有一个事实;意味着它必须是另一个覆盖它的 getter,它不能只是一个属性?
最后的问题,这是处理这种情况的正确方法吗?我是否从根本上误解了 C# 继承的某些部分? 抱歉啰嗦了,但我真的很想了解这里发生了什么。
【问题讨论】:
-
这似乎是一个XY problem,最终是一个设计问题,因为目标/主题类,如果它遵循 SOLID 原则,将依赖于抽象
ISettings而不是具体化,即:Settings,这将导致尝试覆盖成员静音的整个问题,因为它不再与实现细节紧密耦合。 -
好的,这是我没有写的另一个选项,但是是的,只是实现接口及其所有成员似乎是一种更简单的方法,尽管如果有很多我必须实现类的所有成员.
-
@Nkosi - “没有实际意义”,而不是“静音”。
标签: c# unit-testing inheritance polymorphism overriding