我对单元测试有相当多的了解.我一直试图阅读代码合同.它真的有助于单元测试吗?它是否被高估了,特别是当我们谈论有助于进行单元测试的代码合同时.我特指的是.net 4.0中的合同.我使用nunit进行单元测试.
我已经开始使用代码契约,并发现它很难立即发现方法的"胆量".
拿这个(非常简单)的例子:
public static void UserAddNew(string domain, string username, string displayName)
{
Contract.Assert(!string.IsNullOrWhiteSpace(domain));
Contract.Assert(!string.IsNullOrWhiteSpace(username));
Contract.Assert(!string.IsNullOrWhiteSpace(displayName));
LinqDal.User.UserAddNew(domain, username, displayName);
}
Run Code Online (Sandbox Code Playgroud)
现在我很想将合同放在一个区域,以便它们可以被隐藏起来,但是我担心我会失去一个很好的优势,能够浏览方法并看到它的期望.
你怎么做才能让你的合同"整洁"?或者我只是太挑剔了?
我可能会误解代码合同,但这是我的情况.
我有以下代码:
interface IFetch<T> // defined in another DLL
{
T Fetch(int id);
}
interface IUserFetch : IFetch<User>
{
IEnumerable<User> GetUsersLoggedIn ();
}
class UserFetch : IUserFetch
{
public User Fetch(int id)
{
return (User) Database.DoStuff (id);
}
public IEnumerable<User> GetUsersLoggedIn ()
{
return (IEnumerable<User>) Database.DoMoreStuff ();
}
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试添加一个相对简单的合同: Contract.Requires (id != 0);,我想要验证它Fetch.当我直接将其添加到Fetch时,我会收到警告Method Fetch(int id) implements interface 3rdParty.IFetch<User> and thus cannot add Requires.
我创建了一个实现IFetch的抽象代码契约类,ContractClass并ContractClassFor分别使用和属性将其指向/从UserFetch .我仍然得到一个错误CodeContracts: The class 'FetchUserContracts' is …
在我开始使用代码约定之前,有时在使用构造函数链时会遇到与参数验证相关的繁琐.
这是一个(人为的)示例最简单的解释:
class Test
{
public Test(int i)
{
if (i == 0)
throw new ArgumentOutOfRangeException("i", i, "i can't be 0");
}
public Test(string s): this(int.Parse(s))
{
if (s == null)
throw new ArgumentNullException("s");
}
}
Run Code Online (Sandbox Code Playgroud)
我希望Test(string)构造函数链接Test(int)构造函数,并使用int.Parse().
当然,int.Parse()不喜欢有一个null参数,所以如果s为null,它将在我到达验证行之前抛出:
if (s == null)
throw new ArgumentNullException("s");
Run Code Online (Sandbox Code Playgroud)
这使得检查毫无用处.
如何解决?好吧,我有时习惯这样做:
class Test
{
public Test(int i)
{
if (i == 0)
throw new ArgumentOutOfRangeException("i", i, "i can't be 0");
}
public Test(string s): …Run Code Online (Sandbox Code Playgroud) 我在Watch Window尝试观察任何类型时遇到麻烦,我不断收到错误"类型或命名空间名称'[Type]'在此范围内无效".我必须在监视窗口中提供完整的命名空间以及类型来修复此错误.
这只是任何类型的例子 -
如果我添加一个像new Uri(Location) 手表窗口的手表显示错误.所以我应该包含new System.Uri(Location)它的命名空间.这更令人烦恼.
找到此链接,找到它的项目的代码合同设置导致此问题.禁用运行时合同检查代码合同后,Watch/Quick Watch按预期工作.
项目属性 - >代码合同 - >禁用执行运行时合同检查
启用运行时合同检查代码合同有什么问题?代码合同设置有问题吗?或与项目设置有关?或Visual Studio中的错误?
运行Microsoft代码合同时出现以下错误:
CodeContracts:诊断:无法连接到任何缓存.
以下代码在前置条件下失败.这是代码合同中的错误吗?
static class Program
{
static void Main()
{
foreach (var s in Test(3))
{
Console.WriteLine(s);
}
}
static IEnumerable<int>Test (int i)
{
Contract.Requires(i > 0);
for (int j = 0; j < i; j++)
yield return j;
}
}
Run Code Online (Sandbox Code Playgroud) 我目前在ASP.NET MVC应用程序中使用Microsoft Code Contracts没有任何问题,但我似乎无法在基本的ASP.NET网站上运行它.我不完全确定它是用于这种类型的项目(虽然它应该没关系)所以我想把它带给每个人.
我可以很好地编译合同,但代码跳过它们,因为我假设它没有通过属性页面启用,就像你在其他项目类型(即ASP.NET MVC)中那样.我已经进入了我的ASP.NET网站中的项目的属性页面(它显示了一个对话框,而不是典型的属性页面),但它没有产生相同的菜单选项,因此,没有专门的部分编码合同.
此外,我在类库项目中正确启用了Microsoft Code Contracts,我将其用于将业务逻辑与Web站点分离.合同编译正常,但是当合同被违反时,它会抛出一个"Exception of type 'System.ExecutionEngineException' was thrown"没有内部异常的无法提供的错误.我的合同指定了一条在违规时显示的消息,但它不在异常范围内.它只是暂停了进程的执行(我认为这是Microsoft Code Contracts的默认功能).
我找不到任何明确说明特定项目类型可以或不可以(或不应该)与合同一起使用的地方,所以我只是想知道是否有人遇到过这个问题.
谢谢你的帮助!
我最好只用一个代码示例来展示我想要实现的目标?
class SomeClass
{
public int SomeProperty;
public void SomeOperation()
{
Contract.Ensures( "SomeProperty's value has not changed." );
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// How can I write this post-condition?
}
};
Run Code Online (Sandbox Code Playgroud)
(传递给的字符串Contract.Ensures()当然只是真正的后置条件表达式的占位符.)
我怎样才能做到这一点?将Contract.OldValue<>()在这里任何使用的?
很快我和我的兄弟Joel将发布Wing Beats的 0.9版本.它是用F#编写的内部DSL.有了它,您可以生成XHTML.其中一个灵感来源是Ocsigen框架的XHTML.M模块.我不习惯OCaml语法,但我确实理解XHTML.M以某种方式静态检查元素的属性和子元素是否是有效类型.
我们无法在F#中静态检查相同的内容,现在我想知道是否有人知道如何做到这一点?
我的第一个天真的方法是将XHTML中的每个元素类型表示为一个联合案例.但遗憾的是,您无法静态限制哪些案例作为参数值有效,如XHTML.M中所示.
然后我尝试使用接口(每个元素类型为每个有效父类实现一个接口)和类型约束,但是我没有设法使它工作而不使用显式转换,使得解决方案使用起来很麻烦.无论如何,它并不像一个优雅的解决方案.
今天我一直在寻找Code Contracts,但它似乎与F#Interactive不兼容.当我按下alt +输入它冻结.
只是为了让我的问题更加清晰.这是一个同样问题的超简单人工例子:
type Letter =
| Vowel of string
| Consonant of string
let writeVowel =
function | Vowel str -> sprintf "%s is a vowel" str
Run Code Online (Sandbox Code Playgroud)
我希望writeVowel只能静态接受元音,而不是如上所述,在运行时检查它.
我们怎样才能做到这一点?有谁有想法吗?必须有一个聪明的方法来做到这一点.如果没有工会案例,可能还有接口?我一直在努力解决这个问题,但我被困在盒子里,无法想到它.