【问题标题】:Contract.Requires throwing pex errors [duplicate]Contract.Requires抛出pex错误[重复]
【发布时间】:2011-05-01 00:51:42
【问题描述】:

可能重复:
How Do You Configure Pex to Respect Code Contracts?

目前,当我运行 pex 探索时,我在类中创建的代码协定在 pex 探索结果中被视为错误。我认为当您使用代码合同运行 pex 探索时,应将合同失败视为预期行为。 这是导致异常的代码。

测试方法:

[PexMethod]
public void TestEquality(Guid userId, string username, string password, string securityQuestion, string securityAnswer)
{
    UserSecurity user = UserTools.CreateUser(Guid.NewGuid(), username, password, securityQuestion, securityAnswer);

    bool passwordResult = UserTools.VerifyInput(password, user.Password, user.PasswordSalt);
    bool securityAnswerResult = UserTools.VerifyInput(securityAnswer, user.SecurityAnswer, user.SecurityAnswerSalt);

    Assert.IsTrue(passwordResult, "Password did not correctly re-hash");
    Assert.IsTrue(securityAnswerResult, "Security Answer did not correctly re-hash");
}

方法调用失败:

public static UserSecurity CreateUser(Guid userId, string username, string password, string securityQuestion, string securityAnswer)
{
    Contract.Requires(userId != Guid.Empty);
    Contract.Requires(!string.IsNullOrWhiteSpace(username));
    Contract.Requires(!string.IsNullOrWhiteSpace(password));
    Contract.Requires(!string.IsNullOrWhiteSpace(securityQuestion));
    Contract.Requires(!string.IsNullOrWhiteSpace(securityAnswer));
    Contract.Ensures(Contract.Result<UserSecurity>() != null);

    byte[] passwordSalt;
    byte[] securityAnswerSalt;

    return new UserSecurity
               {
                   UserId = userId,
                   Username = username,
                   Password = SecurityUtilities.GenerateHash(password, out passwordSalt),
                   PasswordSalt = passwordSalt,
                   SecurityQuestion = securityQuestion,
                   SecurityAnswer = SecurityUtilities.GenerateHash(securityAnswer, out securityAnswerSalt),
                   SecurityAnswerSalt = securityAnswerSalt,
               };
}

--- 描述

failing test: ContractException, Precondition failed: !string.IsNullOrWhiteSpace(username)

Guid s0
   = new Guid(default(int), (short)32, (short)32, default(byte), default(byte), 
              default(byte), default(byte), default(byte), 
              default(byte), default(byte), default(byte));
this.TestEquality(s0, (string)null, (string)null, (string)null, (string)null);


[TestMethod]
[PexGeneratedBy(typeof(HashTests))]
[PexRaisedContractException]
public void TestEqualityThrowsContractException173()
{
    Guid s0
       = new Guid(default(int), (short)32, (short)32, default(byte), default(byte), 
                  default(byte), default(byte), default(byte), 
                  default(byte), default(byte), default(byte));
    this.TestEquality(s0, (string)null, (string)null, (string)null, (string)null);
}

【问题讨论】:

  • PEX 团队甚至监控这个论坛吗?还是没有更多的 PEX 团队?
  • 我不会称其为“pex 论坛”,即使来自“他们”的人可能会在这里查看。看起来this 是论坛。
  • 我认为他们不再回复了。在 pex 主页上,他们注意到论坛已移至 stackoverflow。 pex home page
  • Ups,应该多加注意。 (当然)甚至在旧论坛上也有一篇关于迁移到 SO 的帖子。对不起。
  • 一切都好!我什至无法找到他们的旧论坛,所以谢谢。 :)

标签: c# c#-4.0 code-contracts pex


【解决方案1】:

根据我对 Pex 的有限经验,我的理解是 Contract 方法定义了达到它们所在方法的先决条件。所以,当你说

Contract.Requires(!string.IsNullOrWhiteSpace(username));

您是说不应该使用 null 或空白用户名参数来访问该语句。 Pex 基本上是在说你错了。这是 Pex 真正 擅长的一件事。这意味着您有可能使用NullReferenceException,或者您没有在对CreateUser 方法的某些调用中检查空/空格username。那么,你的任务就是找到哪里。您可以通过在 CreateUser 方法中处理空/空格 username 来解决此问题,然后为此摆脱 Contract.Requires,或者确保 CreateUser 的所有调用者传递一个非空、非- 空用户名。我认为,更好的选择取决于您的情况,但几乎在所有情况下,我都会在 CreateUser 方法中处理空/空白用户名。这样,您就可以在代码中的一处优雅地处理错误。

当然,您确实应该看到哪个调用者可以传递 null 或空格,因为这可能表明存在用户输入验证问题以及其他潜在问题。

【讨论】:

  • 代码合约是正确的。但是,当您使用 PEX 执行参数化单元测试时,它应该将代码契约视为预期行为。因此,即使合约会在运行时抛出异常,pex 也会按预期处理此异常。 pex 单元测试就是这种情况。我认为这可能是探索结果的一个错误。
  • @Joshua Dale 请参阅research.microsoft.com/en-us/projects/pex/pexandcontracts.pdf 的第 10-11 页。您对“执行运行时合同检查”的设置是什么?
  • 为目标项目启用了合同(为了确定,我也为测试项目启用了它)。我目前也收到一个 ContractException,因此启用了代码合同。
  • 我强烈建议不要在 CreateUser 中处理 null/空格。该方法在没有有效信息的情况下无法执行其工作,并且无论如何都需要抛出异常 - 这正是首先定义前置条件的理想情况。
  • @Morten Mertner 我不确定你在说什么。为什么我不在那个方法中设置一个先决条件?
【解决方案2】:

我发现如果您使用标准合约重写器,请取消勾选失败时断言,并使用类型化的 Requires 参数让您的代码超越 ArgumentNullException。

contract.Requires<ArgumentNullException>(i!=null);

当你这样做时,方法将抛出参数nullexceptions ... pex 与它们表现得非常好。

在编译时,您仍然可以按预期进行合同检查和静态检查。

看起来 PexRaisedContractException 与您使用它的方式不符。我不能说我使用那个属性。我想从你的角度来看,我的方式是一种解决方法;)

编辑:Pex 应该生成这个测试,但是测试应该抛出错误并且应该导致测试通过。这不起作用的事实向我表明,重写器不起作用,或者抛出的异常不是属性正在寻找的异常类型。

【讨论】:

  • 使用代码合约和 pex 时,pex 使用合约失败作为预期异常,并在探索中将其标记为绿色。您的修复确实有效,但同时使用 pex 和代码合同并没有任何好处。
  • '您没有从使用 Pex 和合同中获得任何好处',这是垃圾。以我正在做的方式使用这两种技术对我来说是我代码质量的最大进步。对于无法让它发挥作用的人来说,这是一个相当教条的说法。即使您确实意味着额外的好处,我仍然不同意,因为合同给了我编译时间检查,而 pex 给了我一个很好的探索性测试工具。我厌倦了为空值编写测试......
  • 对不起。我并不是要淡化你的修复,它工作得很好。我只是说它的行为不像以前那样。获得支持比过去在 pex 团队中遇到的问题更加困难。
  • 完全同意支持部分;)我花了一段时间才让人们相信 pex 并没有死......但是由于对代码合同的静态检查的溢价要求,难怪这些东西是硬卖。
  • 同意。这是一个缺乏透明度的伟大产品。我听说 Moles 正在阻止 pex 更新。我不记得我在哪里听到的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多