26

可能重复:
如何配置 Pex 以尊重代码合同?

目前,当我运行 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);
}
4

2 回答 2

0

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

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

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

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

于 2011-05-18T19:46:00.430 回答
0

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

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

当你这样做时,这些方法将抛出 argumentnullexceptions ... pex 对它们表现得非常好。

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

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

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

于 2011-06-24T15:22:17.300 回答