OR 条件的流利断言

Posted

技术标签:

【中文标题】OR 条件的流利断言【英文标题】:Fluent assertion for OR condition 【发布时间】:2016-04-11 19:05:47 【问题描述】:

我正在尝试为以下条件设置流利的断言。但是找不到带有表达式的方法或带有 Or() 的 ObjectAssertion。

我要检查我的服务的状态是枚举值PendingActive

services.Should().HaveCount(totalServices).And.BeOfType<Service>().Which.ServiceStatusKey.Should().Be(Status.Pending);

我想要类似的东西,

.Be(Status.Pending).Or().Be(Status.Active)

谁能帮我实现这个目标。

FluentAsserstions 版本:4.1.1(来自 Nuget 的最新版本) 附加 4.1 FluentAssertions.Primitive 命名空间。

 // Decompiled with JetBrains decompiler
// Type: FluentAssertions.Primitives.ObjectAssertions
// Assembly: FluentAssertions.Core, Version=4.1.1.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a
// MVID: 090116C5-E9A5-4878-B62E-DE0EBFEBBE14
// Assembly location: C:\RA\P4V\BOSS\trunk\M5Portal\packages\FluentAssertions.4.1.1\lib\net45\FluentAssertions.Core.dll

using FluentAssertions;
using FluentAssertions.Common;
using FluentAssertions.Execution;
using System;
using System.Diagnostics;

namespace FluentAssertions.Primitives

  /// <summary>
  /// Contains a number of methods to assert that an <see cref="T:System.Object"/> is in the expected state.
  /// 
  /// </summary>
  [DebuggerNonUserCode]
  public class ObjectAssertions : ReferenceTypeAssertions<object, ObjectAssertions>
  
    /// <summary>
    /// Returns the type of the subject the assertion applies on.
    /// 
    /// </summary>
    protected override string Context
    
      get
      
        return "object";
      
    

    public ObjectAssertions(object value)
    
      this.Subject = value;
    

    /// <summary>
    /// Asserts that an object equals another object using its <see cref="M:System.Object.Equals(System.Object)"/> implementation.
    /// 
    /// </summary>
    /// <param name="expected">The expected value</param><param name="because">A formatted phrase as is supported by <see cref="M:System.String.Format(System.String,System.Object[])"/> explaining why the assertion
    ///             is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
    ///             </param><param name="reasonArgs">Zero or more objects to format using the placeholders in <see cref="!:because"/>.
    ///             </param>
    public AndConstraint<ObjectAssertions> Be(object expected, string because = "", params object[] reasonArgs)
    
      Execute.Assertion.BecauseOf(because, reasonArgs).ForCondition(ObjectExtensions.IsSameOrEqualTo(this.Subject, expected)).FailWith("Expected context:object to be 0reason, but found 1.", expected, this.Subject);
      return new AndConstraint<ObjectAssertions>(this);
    

    /// <summary>
    /// Asserts that an object does not equal another object using its <see cref="M:System.Object.Equals(System.Object)"/> method.
    /// 
    /// </summary>
    /// <param name="unexpected">The unexpected value</param><param name="because">A formatted phrase explaining why the assertion should be satisfied. If the phrase does not
    ///             start with the word <i>because</i>, it is prepended to the message.
    ///             </param><param name="reasonArgs">Zero or more values to use for filling in any <see cref="M:System.String.Format(System.String,System.Object[])"/> compatible placeholders.
    ///             </param>
    public AndConstraint<ObjectAssertions> NotBe(object unexpected, string because = "", params object[] reasonArgs)
    
      Execute.Assertion.ForCondition(!ObjectExtensions.IsSameOrEqualTo(this.Subject, unexpected)).BecauseOf(because, reasonArgs).FailWith("Did not expect context:object to be equal to 0reason.", unexpected);
      return new AndConstraint<ObjectAssertions>(this);
    

    /// <summary>
    /// Asserts that an object is an enum and has a specified flag
    /// 
    /// </summary>
    /// <param name="expectedFlag">The expected flag.</param><param name="because">A formatted phrase explaining why the assertion should be satisfied. If the phrase does not
    ///             start with the word <i>because</i>, it is prepended to the message.
    ///             </param><param name="reasonArgs">Zero or more values to use for filling in any <see cref="M:System.String.Format(System.String,System.Object[])"/> compatible placeholders.
    ///             </param>
    public AndConstraint<ObjectAssertions> HaveFlag(Enum expectedFlag, string because = "", params object[] reasonArgs)
    
      Execute.Assertion.BecauseOf(because, reasonArgs).ForCondition(this.Subject != null).FailWith("Expected type to be 0reason, but found <null>.", (object) expectedFlag.GetType()).Then.ForCondition(this.Subject.GetType() == expectedFlag.GetType()).FailWith("Expected the enum to be of type 0 type but found 1reason.", (object) expectedFlag.GetType(), (object) this.Subject.GetType()).Then.Given<Enum>((Func<Enum>) (() => this.Subject as Enum)).ForCondition((Func<Enum, bool>) (@enum => @enum.HasFlag(expectedFlag))).FailWith("The enum was expected to have flag 0 but found 1reason.", (Func<Enum, object>) (_ => (object) expectedFlag), (Func<Enum, object>) (@enum => (object) @enum));
      return new AndConstraint<ObjectAssertions>(this);
    

    /// <summary>
    /// Asserts that an object is an enum and does not have a specified flag
    /// 
    /// </summary>
    /// <param name="unexpectedFlag">The unexpected flag.</param><param name="because">A formatted phrase explaining why the assertion should be satisfied. If the phrase does not
    ///             start with the word <i>because</i>, it is prepended to the message.
    ///             </param><param name="reasonArgs">Zero or more values to use for filling in any <see cref="M:System.String.Format(System.String,System.Object[])"/> compatible placeholders.
    ///             </param>
    public AndConstraint<ObjectAssertions> NotHaveFlag(Enum unexpectedFlag, string because = "", params object[] reasonArgs)
    
      Execute.Assertion.BecauseOf(because, reasonArgs).ForCondition(this.Subject != null).FailWith("Expected type to be 0reason, but found <null>.", (object) unexpectedFlag.GetType()).Then.ForCondition(this.Subject.GetType() == unexpectedFlag.GetType()).FailWith("Expected the enum to be of type 0 type but found 1reason.", (object) unexpectedFlag.GetType(), (object) this.Subject.GetType()).Then.Given<Enum>((Func<Enum>) (() => this.Subject as Enum)).ForCondition((Func<Enum, bool>) (@enum => !@enum.HasFlag(unexpectedFlag))).FailWith("Did not expect the enum to have flag 0reason.", new object[1]
      
        (object) unexpectedFlag
      );
      return new AndConstraint<ObjectAssertions>(this);
    
  

【问题讨论】:

【参考方案1】:

您可以在这种情况下使用 Match。

ServiceStatusKey.Should().Match<Status>(p=>p==Status.Pending || p == Status.Active);

FluentAssertions 不支持 Or() 语句。将 Match() 用于通用断言。

【讨论】:

【参考方案2】:

试试这个方法:

(services.Status == Status.Pending || services.Status == Status.Active).Should().BeTrue("Message when it is false.");

【讨论】:

这种工作,但如果条件为假,则错误消息不会指示 service.Status 的实际值是什么。 Match() 函数在这方面效果更好。【参考方案3】:

ORAND 难很多,就像

A().Or.B().And.C().Or.D()

是什么意思?

真正的问题是试图支持Or 同时也支持 And。所以 我会考虑编写类似的方法

services.ShouldDoAtLeastOneof(params Predicate predicates)

因为任何更灵活的东西对于单元测试中的断言都是有问题的。

(因为我从未使用过 Fluent Assertions,所以我不知道它是否有内置方法可以做到这一点。我认为 BeOneOf 很好地解决了问题中要求的“OR”的非常有限的情况,如图所示在 Matthew Watson 的回答中。)

【讨论】:

BeOneOf 在 4.1 中不可用 @Raghav,然后自己将其从 4.1 反向移植到您自己的源代码中。 大声笑,非常精明的伊恩。我在想这个,但想知道在简单的情况下是否有一些幼稚的东西。实际上,它所需要的只是检查生成器以防止混合 And 和 Or - 这将解决问题。 Buuut 我刚刚检查了 FluentAssertion 源 - 没有构建器,并且 And 限制在构建器应该存在的地方被烘焙。哦,好吧:)很好的答案【参考方案4】:

如果您可以升级您的 FluentAssertion 版本,那么现在有 BeOneOf 方法可以满足您的需求

【讨论】:

以上是关于OR 条件的流利断言的主要内容,如果未能解决你的问题,请参考以下文章

Python 操作Redis

python爬虫入门----- 阿里巴巴供应商爬虫

Python词典设置默认值小技巧

《python学习手册(第4版)》pdf

Django settings.py 的media路径设置

Python中的赋值,浅拷贝和深拷贝的区别