Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.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
如何对返回Func<;的C#函数进行单元测试;什么东西>;?_C#_Unit Testing_Lambda - Fatal编程技术网

如何对返回Func<;的C#函数进行单元测试;什么东西>;?

如何对返回Func<;的C#函数进行单元测试;什么东西>;?,c#,unit-testing,lambda,C#,Unit Testing,Lambda,我有一个类,其中包含一个方法,该方法返回一个结果对象,该对象包含Func类型的属性 class Result { public Func<Result> NextAction { get; set; } } 类结果{ 公共函数NextAction{get;set;} } 如何编写有关此函数内容的单元测试断言?以下显然不起作用,因为编译器为lambda生成两种不同的方法: // Arrange ListController controller = new ListContr

我有一个类,其中包含一个方法,该方法返回一个结果对象,该对象包含Func类型的属性

class Result {
   public Func<Result> NextAction { get; set; }
}
类结果{
公共函数NextAction{get;set;}
}
如何编写有关此函数内容的单元测试断言?以下显然不起作用,因为编译器为lambda生成两种不同的方法:

// Arrange
ListController controller = new ListController(domain);
// Act
Result actual = controller.DefaultAction();
// Assert
Func<Result> expected = () => new ProductsController(domain).ListAction();
Assert.That(actual.NextAction, Is.EqualTo(expected));
//排列
ListController=新的ListController(域);
//表演
结果实际值=controller.DefaultAction();
//断言
Func预期=()=>新产品控制器(域).ListAction();
Assert.That(actual.NextAction,Is.EqualTo(预期));
我猜我可以用表达式树来代替,但是。。。有没有办法避免这样做?我用的是NUnit2.5

编辑:
结果对象中没有其他标识字段。它是根据当前对象/方法中的决策调用下一个对象/方法的一种方式。

为什么不调用
函数
并比较返回值

var actualValue = actual.NextAction();
var expectedValue = expected();
Assert.That(actualValue, Is.EqualTo(expectedValue));

编辑:我看到结果类没有任何标识。我猜Result类中还有一些其他字段定义了结果的标识,可以用来确定两个结果是否相等。

如果您
Func
总是返回相同的结果,您可以测试函数返回的对象。

我不知道有什么简单的方法可以查看lambda内部(除了您所说的使用表达式树之外)但如果为代理指定了表达式树,则可以对其进行比较


如果您使用lambda,则上面的示例不起作用,因为它们被编译为不同的方法。

那么,对
Func
的内容进行单元测试似乎超出了单元测试的正常范围。a
Func
表示编译后的代码,因此,如果不解析MSIL.In,就无法进一步检查在这种情况下,有必要依赖委托和实例化类型(如Nathan Baulch所建议的),或者使用表达式树

我的表达式树等价物如下:

class Result {
   public Expression<Func<Result>> NextAction { get; set; }
}

请注意,此测试存在一些固有的脆弱性,因为它意味着表达式的结构及其行为。

如果我正确理解此问题,NextAction可能有或可能没有不同的lambda实现,这就是需要测试的内容

在下面的示例中,我比较了IL字节的方法。使用反射,从数组中的正文中获取方法信息和IL字节。如果字节数组匹配,则lambda是相同的

有很多情况,这无法处理,但如果只是比较两个应该完全相同的lambda的问题,这将起作用。很抱歉,它在MSTest中:)

使用系统反射;
....
[测试类]
公共类测试
{
[测试方法]
公共无效结果\u lambdas\u匹配()
{
//安排
ListController testClass=新ListController();
Func预期=()=>newproductsController().ListAction();
实际结果;
字节[]实际方法字节;
字节[]预期方法字节;
//表演
actual=testClass.DefaultAction();
//断言
actualMethodBytes=actual.NextAction。
GetMethodBody().GetILAsByteArray();
expectedMethodBytes=应为。
GetMethodBody().GetILAsByteArray();
//测试阵列是否相同,应该进行更严格的检查
//完成..但这是一个例子:)
for(int count=0;countnewothercontroller().ListAction();
实际结果;
字节[]实际方法字节;
字节[]预期方法字节;
整数计数=0;
//表演
actual=testClass.DefaultAction();
//断言
actualMethodBytes=actual.NextAction。
GetMethodBody().GetILAsByteArray();
expectedMethodBytes=应为。
GetMethodBody().GetILAsByteArray();
//测试数组是否不同,应该进行更多的检查
//完成..但这是一个例子:)
对于(;countnewproductsController().ListAction();
返回结果;
}
}
公共类产品控制器
{
公共结果ListAction(){return null;}
}
公共类控制器
{
公共结果ListAction(){return null;}
}
}

因为Func返回另一个结果对象,带有
class Result {
   public Expression<Func<Result>> NextAction { get; set; }
}
// Arrange
ListController controller = new ListController(domain);
// Act
Result actual = controller.DefaultAction();
// Assert
MethodCallExpression methodExpr = (MethodCallExpression)actual.NextAction.Body;
NewExpression newExpr = (NewExpression)methodExpr.Object;
Assert.That(newExpr.Type, Is.EqualTo(typeof(ProductsController)));
Assert.That(methodExpr.Method.Name, Is.EqualTo("ListAction"));
using System.Reflection;
....


    [TestClass]
    public class Testing
    {
        [TestMethod]
        public void Results_lambdas_match( )
        {
            // Arrange 
            ListController testClass = new ListController( );
            Func<Result> expected = ( ) => new ProductsController( ).ListAction( );
            Result actual;
            byte[ ] actualMethodBytes;
            byte[ ] expectedMethodBytes;

            // Act 
            actual = testClass.DefaultAction( );

            // Assert
            actualMethodBytes = actual.NextAction.
                Method.GetMethodBody( ).GetILAsByteArray( );
            expectedMethodBytes = expected.
                Method.GetMethodBody( ).GetILAsByteArray( );

            // Test that the arrays are the same, more rigorous check really should
            // be done .. but this is an example :)
            for ( int count=0; count < actualMethodBytes.Length; count++ )
            {
                if ( actualMethodBytes[ count ] != expectedMethodBytes[ count ] )
                    throw new AssertFailedException(
                       "Method implementations are not the same" );
            }
        }
        [TestMethod]
        public void Results_lambdas_do_not_match( )
        {
            // Arrange 
            ListController testClass = new ListController( );
            Func<Result> expected = ( ) => new OtherController( ).ListAction( );
            Result actual;
            byte[ ] actualMethodBytes;
            byte[ ] expectedMethodBytes;
            int count=0;

            // Act 
            actual = testClass.DefaultAction( );

            // Assert
            actualMethodBytes = actual.NextAction.
                Method.GetMethodBody( ).GetILAsByteArray( );
            expectedMethodBytes = expected.
                Method.GetMethodBody( ).GetILAsByteArray( );

            // Test that the arrays aren't the same, more checking really should
            // be done .. but this is an example :)
            for ( ; count < actualMethodBytes.Length; count++ )
            {
                if ( actualMethodBytes[ count ] != expectedMethodBytes[ count ] )
                    break;
            }
            if ( ( count + 1 == actualMethodBytes.Length ) 
                && ( actualMethodBytes.Length == expectedMethodBytes.Length ) )
                throw new AssertFailedException(
                    "Method implementations are the same, they should NOT be." );
        }

        public class Result
        {
            public Func<Result> NextAction { get; set; }
        }
        public class ListController
        {
            public Result DefaultAction( )
            {
                Result result = new Result( );
                result.NextAction = ( ) => new ProductsController( ).ListAction( );

                return result;
            }
        }
        public class ProductsController
        {
            public Result ListAction( ) { return null; }
        }
        public class OtherController
        {
            public Result ListAction( ) { return null; }
        }
    }