0

I can't make it work, any help will be much apreciated. There is a list of entities from query response where I would like to test if they are in particular order, and I wish to make the comparison with Fluent assertion library but I have been struggling for hours with the solution. So far I got this:

var prop = typeof(BgTaskListItemDto).GetProperty(orderableAttribute);

listResponse.Data.Entities
     .Select(e => prop.GetValue(e))
     .Should().BeInDescendingOrder()
     .And
     .ThenBeInAscendingOrder(
           e => Expression.Property(               
               Expression.Constant(object:e,
                                   type:typeof(BgTaskListItemDto)),
                                   propertyName:nameof(BgTaskListItemDto.Id)));

where orderableAttribute

is from [DataTestMethod],[DataRow(nameof(BgTaskListItemDto.AccountId))]

evaluating the expression property self return valid data, like:

Expression.Property(Expression.Constant(e, typeof(BgTaskListItemDto)), nameof(BgTaskListItemDto.Id))

or even:

var x = Expression.Lambda(Expression.Property(Expression.Constant(e, typeof(BgTaskListItemDto)), nameof(BgTaskListItemDto.Id))).Compile();

returns value where the e.g.: Id can be found, but using it as parameter for ThenBeInAscendingOrder throw exception:

System.ArgumentException: 
Expression <Property(Constant(e, BgTaskDTOs.BgTaskListItemDto), "Id")> cannot be used to select a member. (Parameter 'expression')

What am I missing? What is the proper use for that method?

Thanks in advance!

alexDuty
  • 72
  • 1
  • 8
  • If you want to generate a dynamic select expression you should be using a `ParameterExpressiond` and a `PropertyExpression`. But your sample doesn't even need it. `ThenBeInAscendingOrder(q=> q.Id)` would do the same. – Eldar Jul 29 '22 at 19:12

2 Answers2

1

You should be able to just write the expression as you would any other lambda. Try performing the projection as part of .BeInDescendingOrder() instead of calling .Select() first — FluentAssertions typically gives the most informative assertion messages if you avoid using .Select() entirely.

var prop = typeof(BgTaskListItemDto).GetProperty(orderableAttribute);

listResponse.Data.Entities
     .Should().BeInDescendingOrder(e => prop.GetValue(e))
     .And.ThenBeInAscendingOrder(e => e.Id);

Expression.Lambda and its related methods are most useful for metaprogramming. If you're reaching for those methods just to do something statically-typed, you have very likely missed a much easier solution.

Tullo_x86
  • 2,573
  • 25
  • 27
  • Actually you have right, the Select() was one problem, but still it throws an exception: `threw exception: System.ArgumentException: Expression c__DisplayClass21_0).prop.GetValue(e), DateTime)> cannot be used to select a member. (Parameter 'expression')` – alexDuty Jul 29 '22 at 22:06
  • 1
    `.BeInDescendingOrder(e => prop.GetValue(e))` this part seems to be problematic. I think that is why op is seeking some dynamic solution. – Eldar Jul 30 '22 at 19:18
  • 1
    Yes @Eldar, that is the problematic, and as @Tullo_x86 pointed out, and according to this https://stackoverflow.com/a/57245755/12743268 article, where `BeEquivalentTo()` has an option param whit this situation should be solved, I will have to chose or an extension method, or the test should not be parameterized. Thank you for your answers, I will mark this question solved. If anyone has an easy solution let me know. – alexDuty Jul 30 '22 at 22:57
0

As in the comment mentioned, according to this article: ThenBeInAscendingOrder accept only property expression. So far I don't see any way to override this, only writing an own extension could hide the workaround. Something like this:

 public static List<T> OrderByAttributeDesc<T>(string orderableAttribute, List<T> response, string pkProperty)
        {
            if (!response.IsAny())
            {
                return response;
            }
            var propertyInfo = GetPropertyInfo(orderableAttribute, response);
            var pkPropertyInfo = GetPropertyInfo(pkProperty, response);

            var entities = response.OrderByDescending(e => propertyInfo.GetValue(e, null)).ThenBy(e => pkPropertyInfo.GetValue(e, null)).ToList();
            return entities;
        }

and then assert the collections in content with fluent collection assertion with configuration options if needed.

alexDuty
  • 72
  • 1
  • 8