简体   繁体   English

在C#中测试/注入私有字段的好习惯是什么?

[英]What are the good practice to test/inject private field in C#

My apologies if this a duplicate. 如果这个重复,我道歉。 I have been given the task to add some coverage for the method and been told to mock the private List<string> property. 我被赋予了为该方法添加一些覆盖的任务,并被告知模拟私有List<string>属性。 My question is: Is there a way to test private fields? 我的问题是: 有没有办法测试私有字段?

The solution I found is adding new constructor just to inject this private list. 我找到的解决方案是添加新的构造函数只是为了注入这个私有列表。 I am not sure whether this is the right way, so any help will be highly appreciated. 我不确定这是否正确,所以任何帮助都将受到高度赞赏。

public class Class1
{
    public Class1(List<string> list)//This is just for Unit Testing 
    {
        list1 = list;
    }


    private readonly InjectRepository _repository;
    //
    public Class1(InjectRepository repository)//This is the actual constructor
    {
        _repository = repository;
    }

    private List<string> list1 = new List<string>();

    public void Do_Complex_Logic()
    {
       //list1 will be set with items in it
       //Now list1 is passed to some other instance
    }
}

The private logic of a class should be visible in the public expression of its behavior. 类的私有逻辑应该在其行为的公共表达中可见。 In other words, the theory goes, there should be no need to test private fields at all. 换句话说,理论上说,根本不需要测试私有字段。

There is no way to directly test private fields; 无法直接测试私有字段; they are private after all. 毕竟他们是私人的。 If you really think that testing a private field is required, then I would suggest making it internal instead, and exposing it to your unit testing assemblies via the [InternalsVisibleTo] attribute. 如果您真的认为需要测试私有字段,那么我建议将其设置为内部,并通过[InternalsVisibleTo]属性将其公开给您的单元测试程序集。

That being said, there are frameworks that allow such things, such as TypeMock . 话虽这么说,有些框架允许这样的事情,比如TypeMock

Don't test private fields or methods. 不要测试私有字段或方法。 Test the behaviour of a contract - public or internal methods. 测试合同的行为 - 公共或内部方法。

That said, you can try: 那说,你可以尝试:

Option A 选项A.
Make private members internal and set InternalsVisibleTo attribute for the assembly under test. 使私有成员内部并为要测试的程序集设置InternalsVisibleTo属性。

Option B 选项B.
Write a wrapper class that wraps you private fields/methods into public ones. 编写一个包装类,将私有字段/方法包装到公共字段/方法中。 This approach has a benefit that you don't need to make your private methods internal. 这种方法的好处是您不需要将私有方法设置为内部方法。 The downside is that for every private method you will have a wrapper public method. 缺点是,对于每个私有方法,您将拥有一个包装器公共方法。 So the amount of methods may double. 所以方法的数量可能会翻倍。

Adding to what womp & oleksii have already said - 添加到womp&oleksii已经说过 -

The fact that you want/need to test a private method is a sign (smell?) that your design may be incorrect. 您希望/需要测试私有方法的事实是一个标志(气味?),您的设计可能不正确。 This is one of the positive side-effects of TDD (and my personal favorite). 这是TDD(以及我个人最喜欢的)的积极副作用之一。

An example: 一个例子:

I don't fully know your domain here, but one simple change could be to, instead of Do_Complex_Logic taking no parameters, you could have it take and return a List<string> : 我在这里并不完全了解你的域名,但是一个简单的改变可能是,而不是没有参数的Do_Complex_Logic ,你可以让它接受并返回一个List<string>

public List<string> Do_Complex_Logic( List<string> input )

I know - it's simple , but try deconstructing your class a bit and build it back with the tests in mind first. 我知道 - 这很简单 ,但是请尝试解构一下你的课程,然后首先考虑测试。

I'm not disagreeing with the other answers; 我不同意其他答案; but in this case I think the most appropriate thing to do - given your code; 但在这种情况下,我认为最合适的事情是 - 给出你的代码; is to change the signature of 是改变签名

'Do_Complex_Logic' 'Do_Complex_Logic'

The real problem is that you are dealing with the 'state' of List1. 真正的问题是你正在处理List1的'状态'。 If you pass List1 into Do_Complex_Logic - your problem is mostly solved. 如果将List1传递给Do_Complex_Logic - 您的问题基本上已得到解决。 Your comment says that 'Do_Complex_Logic' is going to (presumably) do some work on List1 and then pass it into something else, right? 您的评论说'Do_Complex_Logic'将(可能)在List1上做一些工作,然后将其传递给其他东西,对吧?

Make Do_Complex_Logic take a List and return a List. 使Do_Complex_Logic获取List并返回List。 Now it's easy to test. 现在很容易测试。 Instead of depending on the state of List1 being setup correctly in your class, you can 'inject the dependency'. 您可以“注入依赖项”,而不是依赖于在类中正确设置List1的状态。

How does the private field get prepared in the first place? 私人领域如何在第一时间做好准备? If it is through interactions with the repository then you could possibly mock that object. 如果是通过与存储库的交互,那么您可能会模拟该对象。

One way to do that is to interact with your repository through an interface (let's call it IInjectRepository rather than a concrete entity and then use something like Moq (or one of the many plethora of mocking frameworks out there) to populate your data via a mock'd repository as you setup your test. After you have called Do_Complex_Logic I assume you have a way of interrogating the entity so that you know it has done what you expected to. This way you can avoid/mitigate adding methods and classes that are for test only. 一种方法是通过接口与您的存储库进行交互(让我们称之为IInjectRepository而不是具体的实体,然后使用类似Moq (或其中许多模拟框架中的一个)来通过模拟填充您的数据在设置测试时存储库。在调用Do_Complex_Logic我假设您有一种询问实体的方法,以便您知道它已经完成了您的预期。这样您就可以避免/减轻添加的方法和类仅测试。

You could use reflection as mensioned in answer https://stackoverflow.com/a/3376157/1523402 of a related question. 您可以在回答相关问题的https://stackoverflow.com/a/3376157/1523402中使用反射
I don't know if private accessors also work for private fields. 我不知道私人访问者是否也适用于私人领域。 But they help (at least) for private methods (see http://msdn.microsoft.com/en-us/library/ms184807%28v=vs.80%29.aspx ). 但它们(至少)帮助私有方法(请参阅http://msdn.microsoft.com/en-us/library/ms184807%28v=vs.80%29.aspx )。

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

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