OO 中的单元测试和访问修饰符

Unit Testing and Access modifiers in OO

本文关键字:访问 单元测试 OO      更新时间:2023-10-16

我注意到,为了对OO代码中的每个单元进行单元测试,我需要将访问修饰符设置为公共,即使在应该受保护或可能是私有的方法上也是如此。这是可以练习的吗?

public class EnforceBusinessRules
{
    BusinessState m_state;
    public EnforceBusinessRules()
    {
        m_state = START;
    }

    public bool isInputcurrentlyFormatted(string input)
    {
        //code goes here to ensure the input passes formatting test
        //modify m_state appropriately
    }

    public bool InputContainsValidStartAndEndTokens(string input)
    {
        //code goes here to ensure that the start and end tokens of the input are of the type available in the system
        //modify m_state appropriately
    }

    public bool StartEndCommandisValidAccordingtoCurrentSystemSettings(string input)
    {
        //code goes here to check the start and End codes match the current start and end codes for the day
        //modify m_state appropriately
    }
    // and so on 
}

单元测试是"黑盒"测试。您应该只测试外部可见元素。如果你测试了所有的内部工作,那么如果不修改所有的单元测试,你就无法正确地重构你的代码。

如果您发现需要更改访问修饰符,因为私有成员中有大量代码需要测试,这可能表明您的类太大。 考虑将要测试的行为分解为具有可测试的公共接口的较小类。 您的代码可能正在遭受上帝对象代码气味的困扰。

请记住,受保护的成员与公共成员非常相似,只是可能的客户端的空间要小得多(仅限派生类)。 您可以考虑通过创建仅测试使用的派生对象来对这些方法进行单元测试。 这样,您将以与客户使用它们相同的方式测试这些方法。

以下是修改代码的一种方法:

public class EnforceBusinessRules
{
    BusinessState m_state;
    public EnforceBusinessRules(IEnumerable<Rule> rules)
    {
        m_state = START;
    }
    public void Enforce(string input)
    {
        foreach (var rule in rules)
        {
            m_state = rule.EnforceRule(input);
        }
    }
}
public interface Rule
{
    public BusinessState EnforceRule(string input);
}
public class IsInputcurrentlyFormatted : Rule
{
    public BusinessState EnforceRule(string input)
    {
        //code goes here to ensure the input passes formatting test
    }
}
public class InputContainsValidStartAndEndTokens : Rule
{
    public BusinessState EnforceRule(string input)
    {
        //code goes here to ensure the input passes formatting test
    }
}
public class StartEndCommandisValidAccordingtoCurrentSystemSettings : Rule
{
    public BusinessState EnforceRule(string input)
    {
        //code goes here to ensure the input passes formatting test
    }
}
// and so on

No.在我看来,你想错了。你可以在不公开的情况下推断事物。例如,属性的值可以从函数返回中实现。

在受保护成员的情况下。问问自己这意味着什么。这意味着派生类可以访问该成员。因此,在测试中创建一个派生类型。

听起来您未能创建 getter 和 setter 方法,以便正确封装您的私有数据。

单元测试应通过 getter 和 setter 访问数据。

避免在类代码中实例化协作对象,而是注入这些依赖项。

通常,将方法/类/属性/任何内容公开给您不想公开的外部世界都是不好的做法。 我们在我工作的地方遇到了类似的问题。 我们编写了命中公共方法和属性的测试,因为这些公共方法应该在某个时候调用所有私有方法。 如果您有内部类/属性/方法,则可以使用 InternalsVisableTo 属性来访问单元测试库。

[assembly: InternalsVisibleTo("AssemblyB")]

http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx

如果需要测试私有或受保护的属性或方法,则应将功能提取到单独的类中。每个类应该只做一件事(单一责任原则)。您的私有方法很可能在类的主要目的上执行辅助功能。

提取后,会发生两件好事:首先,您希望测试的代码现在可以通过单元测试完全访问。其次,您不必担心在EnforceBusinessRules课程中