Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中的单元测试私有方法#_C#_Unit Testing_Mstest - Fatal编程技术网

C# C语言中的单元测试私有方法#

C# C语言中的单元测试私有方法#,c#,unit-testing,mstest,C#,Unit Testing,Mstest,VisualStudio允许通过自动生成的访问器类对私有方法进行单元测试。我编写了一个私有方法的测试,该方法编译成功,但在运行时失败。代码和测试的最低版本为: //in project MyProj class TypeA { private List<TypeB> myList = new List<TypeB>(); private class TypeB { public TypeB() {

VisualStudio允许通过自动生成的访问器类对私有方法进行单元测试。我编写了一个私有方法的测试,该方法编译成功,但在运行时失败。代码和测试的最低版本为:

//in project MyProj
class TypeA
{
    private List<TypeB> myList = new List<TypeB>();

    private class TypeB
    {
        public TypeB()
        {
        }
    }

    public TypeA()
    {
    }

    private void MyFunc()
    {
        //processing of myList that changes state of instance
    }
}    

//in project TestMyProj           
public void MyFuncTest()
{
    TypeA_Accessor target = new TypeA_Accessor();
    //following line is the one that throws exception
    target.myList.Add(new TypeA_Accessor.TypeB());
    target.MyFunc();

    //check changed state of target
}
根据intellisense,因此我猜编译器目标是类型A_访问器。但在运行时,它的类型是TypeA,因此列表添加失败


有什么方法可以阻止这个错误吗?或者,更可能的是,其他人还有什么建议(我预测可能是“不要测试私有方法”和“不要让单元测试操纵对象的状态”)。

是的,不要单元测试私有方法。。。。单元测试的思想是通过其公共“API”来测试单元

如果您发现需要测试大量的私有行为,那么很可能您有一个新的“类”隐藏在您尝试测试的类中,提取它并通过它的公共接口进行测试

一条建议/思考工具。。。。。有一种观点认为,任何方法都不应该是私有的。这意味着所有方法都应该存在于对象的公共接口上。。。。如果你觉得需要将其保密,它很可能存在于另一个对象上


这条建议在实践中不太管用,但它大多是好建议,通常会促使人们将其对象分解为更小的对象。

这里的另一个想法是将测试扩展到“内部”类/方法,使这种测试更具白盒感。您可以在程序集上使用InternalsVisibleToAttribute将这些属性公开给单独的单元测试模块

结合密封类,您可以实现这样的封装,即测试方法只能从您的方法的UnitTestAssembly中看到。考虑到密封类中的受保护方法实际上是私有的。< /P>
[assembly: InternalsVisibleTo("MyCode.UnitTests")]
namespace MyCode.MyWatch
{
    #pragma warning disable CS0628 //invalid because of InternalsVisibleTo
    public sealed class MyWatch
    {
        Func<DateTime> _getNow = delegate () { return DateTime.Now; };


       //construktor for testing purposes where you "can change DateTime.Now"
       internal protected MyWatch(Func<DateTime> getNow)
       {
           _getNow = getNow;
       }

       public MyWatch()
       {            
       }
   }
}
[汇编:InternalsVisibleTo(“MyCode.UnitTests”)]
名称空间MyCode.MyWatch
{
#pragma warning disable CS0628//由于内部可视性而无效
公共密封级MyWatch
{
Func_getNow=delegate(){return DateTime.Now;};
//用于测试目的的构造函数,其中“可以立即更改日期时间”
内部保护MyWatch(Func getNow)
{
_getNow=getNow;
}
公共MyWatch()
{            
}
}
}
和单元测试:

namespace MyCode.UnitTests
{

[TestMethod]
public void TestminuteChanged()
{
    //watch for traviling in time
    DateTime baseTime = DateTime.Now;
    DateTime nowforTesting = baseTime;
    Func<DateTime> _getNowForTesting = delegate () { return nowforTesting; };

    MyWatch myWatch= new MyWatch(_getNowForTesting );
    nowforTesting = baseTime.AddMinute(1); //skip minute
    //TODO check myWatch
}

[TestMethod]
public void TestStabilityOnFebruary29()
{
    Func<DateTime> _getNowForTesting = delegate () { return new DateTime(2024, 2, 29); };
    MyWatch myWatch= new MyWatch(_getNowForTesting );
    //component does not crash in overlap year
}
}
namespace MyCode.UnitTests
{
[测试方法]
public void TestminuteChanged()
{
//及时观察交通情况
DateTime baseTime=DateTime.Now;
DateTime nowforTesting=基准时间;
Func_getNowForTesting=delegate(){return nowforTesting;};
MyWatch MyWatch=新的MyWatch(\u GetNow用于测试);
nowforTesting=baseTime.AddMinute(1);//跳过分钟
//我要检查我的手表
}
[测试方法]
2月29日公开作废测试稳定性()
{
Func_getNowForTesting=delegate(){返回新的日期时间(2024,2,29);};
MyWatch MyWatch=新的MyWatch(\u GetNow用于测试);
//组件不会在重叠年份崩溃
}
}
您可以使用该类:

Class目标=新类();
PrivateObject obj=新的PrivateObject(目标);
var retVal=obj.Invoke(“PrivateMethod”);
Assert.AreEqual(expectedVal、retVal);
注:
PrivateObject
PrivateType
不适用于以netcoreapp2.0为目标的项目-

“没有所谓的标准或最佳实践,它们可能只是流行意见”。 这一讨论也是如此

这完全取决于你认为什么是单元,如果你认为单元是一个类,那么你只会点击公共方法。若你们认为单位是代码行,那个么打击私有方法不会让你们感到内疚


如果要调用私有方法,可以使用“PrivateObject”类并调用invoke方法。您可以观看这段深入的youtube视频(),它展示了如何使用“PrivateObject”,还讨论了私有方法的测试是否符合逻辑。

在VS2005/2008中,您可以使用它来测试私有成员,但在VS的更高版本中,这种方法是消失的测试私有方法的一种方法是通过反射。这也适用于NUnit和XUnit:

MyObject objUnderTest = new MyObject();
MethodInfo methodInfo = typeof(MyObject).GetMethod("SomePrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
object[] parameters = {"parameters here"};
methodInfo.Invoke(objUnderTest, parameters);

将私有方法提取到另一个类,对该类进行测试;了解有关SRP原则(单一责任原则)的更多信息

似乎需要将
private
方法提取到另一个类;在这应该是
public
。您应该测试另一个类的
public
方法,而不是尝试测试
private
方法

我们有以下情况:

Class A
+ outputFile: Stream
- _someLogic(arg1, arg2) 
我们需要测试
\u someLogic
的逻辑;但似乎
A类
的作用超出了其需要(违反了SRP原则);只需重构成两个类

Class A1
    + A1(logicHandler: A2) # take A2 for handle logic
    + outputFile: Stream
Class A2
    + someLogic(arg1, arg2) 

这样就可以在A2上测试
someLogic
;在A1中,只需创建一些伪A2,然后将其注入构造函数,以测试A2是否被调用到名为
someLogic

Ermh的函数。。。这里出现了完全相同的问题:测试一个简单但关键的私有方法。读过这条线后,它看起来像是“我想在这片简单的金属上钻这个简单的孔,我想确保质量符合规格”,然后就来了“好吧,这可不容易。首先,目前还没有合适的工具,但你可以在花园里建立一个引力波观测站。首先阅读我的文章,当然,你必须参加一些高级量子物理课程,然后你需要大量的超冷氮,然后,当然,我的书可以在亚马逊上买到“

换句话说

不,首先要做的事

每一种方法,可能都是私有的、内部的、受保护的、公共的都是可测试的。必须有一种方法来实现这些测试,而不需要像这里介绍的那样费事

为什么?正是因为建筑师
Class A1
    + A1(logicHandler: A2) # take A2 for handle logic
    + outputFile: Stream
Class A2
    + someLogic(arg1, arg2) 
[TestFixture]
public class UnitTests : ObjectWithPrivateMethods
{
    [Test]
    public void TestSomeProtectedMethod()
    {
        Assert.IsTrue(this.SomeProtectedMethod() == true, "Failed test, result false");
    }
}
 public static  TReturn CallPrivateMethod<TReturn>(
        this object instance,
        string methodName,
        params object[] parameters)
    {
        Type type = instance.GetType();
        BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Instance;
        MethodInfo method = type.GetMethod(methodName, bindingAttr);

        return (TReturn)method.Invoke(instance, parameters);
    }
Calculator systemUnderTest = new Calculator();
int result = systemUnderTest.CallPrivateMethod<int>("PrivateAdd",1,8);