简体   繁体   English

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

[英]Unit Testing and Access modifiers in OO

I notice that in order to unit test each unit in my OO code, I need to set the access modifiers to public, even on methods that ought to be protected, or probably private. 我注意到为了在我的OO代码中对每个单元进行单元测试,我需要将访问修饰符设置为public,即使是应该受到保护的方法,也可能是私有的。 Is this OK practice? 这可以吗?

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 
}

Unit testing is "Black box" testing. 单元测试是“黑盒子”测试。 You should only test the externally visible elements. 您应该只测试外部可见元素。 If you test all the internal workings then you can't refactor your code correctly without modifying all your unit tests. 如果您测试所有内部工作,那么在不修改所有单元测试的情况下,您无法正确重构代码。

If you find that you need to change access modifiers because you have plenty of code in private members that you need to test, it may be a sign that your class is too large. 如果您发现需要更改访问修饰符,因为您需要测试私有成员中的大量代码,这可能表明您的类太大了。 Consider breaking the behavior you want to test into smaller classes with public interfaces that you can test. 考虑使用可以测试的公共接口将要测试的行为分解为较小的类。 Your code may be suffering from the god object code smell. 你的代码可能会遭受上帝对象代码的嗅觉。

Remember that protected members are very similar to public members, except that the space of possible clients is much smaller (derived classes only). 请记住,受保护的成员与公共成员非常相似,只是可能的客户端空间要小得多(仅限派生类)。 You could consider unit testing those methods by creating a derived object which only your test uses. 您可以考虑通过创建只有您的测试使用的派生对象来对这些方法进行单元测试。 In this way, you will be testing these methods in the same manner your clients will use them. 通过这种方式,您将以与客户端使用它们相同的方式测试这些方法。

Here is one way that you might modify your code: 以下是修改代码的一种方法:

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. You are thinking about it wrongly in my opinion. 不,我认为你错误地考虑了这个问题。 You can infer things without making things public. 你可以在不公开的情况下推断事物。 A property's value could be realised from a function return for example. 例如,可以从函数返回实现属性的值。

In the case of a protected member. 在受保护成员的情况下。 Ask your self what that means. 问问自己这意味着什么。 It means that derived classes can access that member. 这意味着派生类可以访问该成员。 So make a derived type in the test. 因此,在测试中创建派生类型。

Typically it is bad practice to expose methods/classes/properties/whatever to the outside world you don't want to expose. 通常,将方法/类/属性/任何内容暴露给您不希望公开的外部世界是不好的做法。 We ran into a similar issue where I work. 我遇到了类似的问题。 We wrote tests that hit the public methods and properties, because those public methods should, at some point, invoke all the private methods. 我们编写了针对公共方法和属性的测试,因为这些公共方法在某些时候应该调用所有私有方法。 In the case where you have internal classes/properties/methods you can use the InternalsVisableTo attribute to them accessible to your unit testing library. 如果您有内部类/属性/方法,则可以使用InternalsVisableTo属性来访问单元测试库。

[assembly: InternalsVisibleTo("AssemblyB")]

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

It sounds like you are failing to create getter and setter methods so that your private data is correctly encapsulated . 听起来您无法创建getter和setter方法,以便正确封装您的私有数据。

The unit tests should access data via getters and setters. 单元测试应该通过getter和setter访问数据。

Avoid instantiating collaborating objects in your class code, inject those dependencies instead. 避免在类代码中实例化协作对象,而是注入这些依赖项

If you need to test private or protected properties or methods, then you should extract the functionality into separate classes. 如果需要测试私有或受保护的属性或方法,则应将功能提取到单独的类中。 Each class should only do one thing (Single Responsibility Principle). 每个班级应该只做一件事(单一责任原则)。 Odds are that your private methods perform the secondary functionality on the main purpose of your class. 可能的情况是,您的私有方法在您的类的主要目的上执行辅助功能。

When extracted, two good things happen: First, the code you wish to test is now fully accessible by unit tests. 解压缩后,会发生两件好事:首先,您希望测试的代码现在可以通过单元测试完全访问。 Second, you don't have to worry about it in your EnforceBusinessRules class. 其次,您不必在EnforceBusinessRules类中担心它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM