2011-05-01 79 views
25

可能重复:
How Do You Configure Pex to Respect Code Contracts?Contract.Requires抛出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); 
} 
+0

PEX团队是否会监督这个论坛?还是没有更多的PEX团队? – 2011-05-05 01:39:15

+1

我不会称之为“pex论坛”,即使来自“他们”的人可能会在此处查看。看起来像[这](http://social.msdn.microsoft.com/Forums/en-US/pex/threads/)是论坛。 – 2011-05-09 12:33:20

+1

我不认为他们在那里回应。在pex主页上,他们记下论坛已被移至stackoverflow。 [PEX主页](http://research.microsoft.com/en-us/projects/pex/) – 2011-05-10 01:26:02

回答

0

我的理解,我与Pex的经验有限,就是Contract方法定义了达到他们所处方法的先决条件。所以,当你说

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

你是说应该没有办法用空白或空白的用户名参数来达到这个声明。佩克斯基本上是说你错了。这是Pex的一件事真的有益。这意味着您有可能获得NullReferenceException或者在您拨打CreateUser方法时未检查空白/空白username。那么你的任务就是找到哪里。您可以通过处理CreateUser方法中的空白/空白username,然后删除Contract.Requires或通过确保CreateUser的所有呼叫者传递非空非空用户名来解决问题。我认为更好的选择取决于你的情况,但在几乎所有情况下,我都会在CreateUser方法中处理空白/空白用户名。这样,您可以在代码中的一个地方优雅地处理错误。

当然,你真的应该看到哪个调用者可以传递null或空白,因为这可能表示用户输入验证问题以及其他潜在问题。

+0

代码合同正确。但是,当您使用PEX执行参数化单元测试时,应该将代码合同视为预期的行为。所以,即使合同会在运行时抛出一个异常,pex会按预期处理这个异常。 pex单元测试就是这种情况。我认为这可能是勘探结果的一个缺陷。 – 2011-05-19 17:27:47

+0

@Joshua Dale参见http://research.microsoft.com/en-us/projects/pex/pexandcontracts.pdf的第10-11页。 “执行运行时合同检查”的设置是什么? – Andrew 2011-05-19 17:59:06

+0

为目标项目打开合同(我也为测试项目启用了合约)。此外,我正在获得一个ContractException,因此代码合同已启用。 – 2011-05-20 01:17:02

0

我发现如果您使用标准合约重写器,请在发生故障时不要触发assert,并让您的代码通过使用类型化的Requires参数来触发ArgumentNullException。

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

当你这样做的时候,这些方法会抛出argumentnullexceptions ... pex的表现与他们完全吻合。

在编译时您仍然可以像您期望的那样获得合同检查和静态检查。

它看起来像PexRaisedContractException不与您如何使用它的行为。我不能说我使用该属性。我想从你的角度来看,我的方式是一个工作;)

编辑:Pex应该产生这个测试,但测试应该抛出错误,并应该导致测试通过。这不起作用的事实表明,重写器无法正常工作,或者抛出的异常不属于属性查找的异常类型。

+0

当使用代码合同和pex时,pex使用合同失败作为预期的异常,并在探索中将其标记为绿色。您的修复程序确实有效,但您同时使用pex和代码合同并不会带来任何好处。 – 2011-07-02 07:12:11

+0

'使用Pex和Contracts'是垃圾,您从中受益无益。按照我所做的方式使用这两种技术是我的代码质量的最大进步。对于无法工作的人来说,这是一个相当教条的陈述。即使你确实意味着额外的好处,我仍然不同意,因为合同给我编译时间检查,pex为我提供了一个探索性测试的好工具。我厌倦了为空值编写测试.... – 2011-07-04 12:42:28

+0

对不起。我不是故意淡化你的修复,这很好。我只是简单地说它并不像它用来做的那样。获得支持比使用Pex团队更成问题。 – 2011-07-04 14:20:08