Build/Test Issues

Generic Test passes under NUnity but not NCrunch

Started by bjjenson on 7,007 views

The following test passes fine under NUnit but does not pass under NCrunch.

[TestCase((int)5, (int)6)]
[TestCase((long)5, (long)6)]
[TestCase((short)5, (short)6)]
[TestCase((double)5.6, (double)6.5)]
[TestCase((float)5.6, (float)6.5)]
[TestCase((bool)true, (bool)false)]
public void CreateFilterExpression_value_equalsOperator<T>(T equalValue, T otherValue)
{
var data = new GenericTestModel<T>[] {
new GenericTestModel<T>{ Value = equalValue},
new GenericTestModel<T> { Value = otherValue},
};
Expression<Func<GenericTestModel<T>, object>> expression = t => t.Value;
T value = equalValue;

var filterExpression = ExpressionBuilder.CreateFilterExpression<GenericTestModel<T>>(expression, value.ToString());

Assert.AreEqual(1, data.Count(filterExpression.Compile()));
}

I would rather not have to write and maintain 6 different tests but will have to do so for the time being. Any suggestions?
Hi, thanks for sharing this issue.

Is there any chance you could share the code for the ExpressionBuilder and GenericTestModel classes? If you like, you can submit this privately using the contact form. With these components I may be able to reproduce the behaviour you're seeing.

If you haven't already, I recommend reading up on the test troubleshooting page, as this page contains many useful suggestions for troubleshooting issues such as this. NCrunch itself uses NUnit to run your test, so this problem is likely to be caused by a difference between NCrunch's test environment and the test environment the test was designed in. Usually such issues can be resolved with minor modifications to the test or introducing additional NCrunch configuration.


Cheers,

Remco
Here is the code for ExpressionBuilder.


    public static class ExpressionBuilder
    {
        public static Expression<Func<TModel, bool>> CreateFilterExpression<TModel>(LambdaExpression parameterExpression, string value)
        {
            Type propertyType = GetPropertyType(parameterExpression);
            Func<Expression, Expression, Expression> operatorExpression = null;

            if (propertyType == typeof(string))
            {
                var containsMethod = typeof(string).GetMethod("Contains");
                operatorExpression = (left, target) => Expression.Call(left, containsMethod, target);
            }
            else if (propertyType == typeof(int) ||
                propertyType == typeof(long) ||
                propertyType == typeof(short) ||
                propertyType == typeof(double) ||
                propertyType == typeof(float) ||
                propertyType == typeof(bool))
            {
                operatorExpression = (left, target) => Expression.Equal(left, target);
            }
            else
            {
                throw new NotImplementedException("GetType is not imlemented yet for " + propertyType.ToString());
            }

            return CreateFilterExpression<TModel>(parameterExpression, value, operatorExpression);
        }

        public static Expression<Func<TModel, bool>> CreateFilterExpression<TModel>(LambdaExpression parameterExpression, string value, Func<Expression, Expression, Expression> createOperator)
        {
            var expressions = new List<Expression>();

            ParameterExpression argParam = parameterExpression.Parameters.First();
            var nameMember = GetExpressionMember(parameterExpression);

            var prop = (PropertyInfo)nameMember;
            object typedValue = Convert.ChangeType(value, prop.PropertyType, null);

            Expression equalTarget = Expression.Constant(typedValue, prop.PropertyType);
            Expression left = Expression.PropertyOrField(argParam, nameMember.Name);
            Expression equals = createOperator(left, equalTarget);

            return Expression.Lambda<Func<TModel, bool>>(equals, argParam);
        }

        public static Expression<Func<TModel, bool>> CombineFilters<TModel>(Expression<Func<TModel, bool>> left, Expression<Func<TModel, bool>> right)
        {
            var expressionArg = left.Parameters.First();
            BinaryExpression andedExpression = Expression.AndAlso(left.Body, Expression.Invoke(right, expressionArg));

            return Expression.Lambda<Func<TModel, bool>>(andedExpression, expressionArg);
        }

        private static Type GetPropertyType(LambdaExpression parameterExpression)
        {
            var propertyInfo = (PropertyInfo)GetExpressionMember(parameterExpression);
            return propertyInfo.PropertyType;
        }

        public static MemberInfo GetExpressionMember(LambdaExpression lambda)
        {
            var property = lambda.Body as MemberExpression;
            if (property != null)
            {
                return property.Member;
            }

            var unary = lambda.Body as UnaryExpression;
            if (unary != null)
            {
                return ((MemberExpression)unary.Operand).Member;
            }

            throw new NotImplementedException(lambda.Body.GetType().ToString() + " is not implemented");
        }
    }


And GenericTestModel


public class GenericTestModel<TValue>
{
    public TValue Value { get; set; }
}
Can you confirm whether you have your Framework utilisation type for NUnit set to StaticAnalysis? If so, this test will cause you problems.

StaticAnalysis is slightly faster than DynamicAnalysis with NUnit, but it does not provide full support for all niche NUnit features (such as complex TestCases). In order to run this test with NCrunch in its current structure, you must use DynamicAnalysis.


Cheers,

Remco
Yes it is set to use StaticAnalysis.

Thanks

Post a reply

Log in to reply.