当前位置: 首页 > 编程语言 > C#

SpecFlow和复杂对象共享

时间:2023-04-10 15:27:05 C#

SpecFlow和复杂对象我正在评估SpecFlow,我有点卡住了。我找到的所有样本基本上都是简单的对象。我正在从事的项目在很大程度上依赖于复杂的对象。一个接近的例子可能是这个对象:publicclassMyObject{publicintId{get;放;}publicDateTimeStartDate{get;放;}publicDateTimeEndDate{get;放;}publicIListChildren{get;放;}}publicclassChildObject{publicintId{get;放;}公共字符串名称{得到;放;}publicintLength{得到;“步骤实例化并在“When”和“Then”步骤中使用?提前致谢编辑:只是一个想法:支持嵌套表?对于你展示的例子,我会说你错了。这个例子看起来更好用nunit编写,可能有一个对象父对象。使用specflow或类似工具编写的测试应该面向客户,并使用客户用来描述功能的相同语言。我想说Marcus几乎就在这里,但我会写我的方案,因此我可以在TechTalk.SpecFlow.Assist命名空间中使用一些扩展方法。请参见此处。鉴于我有以下孩子:|编号|名称|长度||1|约翰|26||2|凯特|21|鉴于我有以下MyObject:|领域|价值||编号|1||开始日期|01/2011||结束日期|2011年1月1日||儿童|1,2|对于步骤背后的代码,你可以使用类似这样的东西,它会有更多的错误处理。[Given(@"我有以下孩子:")]publicvoidGivenIHaveTheFollowingChildren(Tabletable){ScenarioContext.Current.Set(table.CreateSet());}[Given(@"IhaveenteredthefollowingMyObject:")]publicvoidGivenIHaveEnteredTheFollowingMyObject(Tabletable){varobj=table.CreateInstance();varchildren=ScenarioContext.Current.Get>();obj.Children=newList();foreach(varrowintable.Rows){if(row["Field"].Equals("Children")){foreach(varchildIdinrow["Value"].Split(newchar[]{','},StringSplitOptions.RemoveEmptyEntries)){obj.Children.添加(孩子.Where(孩子=>child.Id.Equals(Convert.ToInt32(childId))).First());希望这个(或其中的一些)能帮助你我建议你尽量保持场景的清洁,重点放在项目中非技术人员的可读性上。然后,在步骤定义中处理如何构造复杂对象图。话虽如此,您还需要一种方法来表达规范中的层次结构,即使用Gherkin。据我所知,这是不可能的,从这篇文章(在SpecFlowGoogle组中)看来,之前已经讨论过了。基本上你可以发明自己的格式并在你的步骤中解析它。我自己还没有遇到过这个问题,但我想我会尝试下一个包含空白值的表并在步骤定义中解析它。像这样:鉴于我有以下层次结构:|我的对象。开始日期|结束日期|子对象。名称|长度||1|20010101|||2|你|120|我承认它不是超级漂亮,但它确实有效。另一种方法是使用默认值并给出差异。像这样:给定一个标准的MyObject和以下孩子:|编号|名称|长度||1|我|196||2|你|物品清单。如果您问我,该方法有点可读性,但您必须“知道”什么是标准MyObject以及它是如何配置的。基本上-Gherkin不支持它。但是您可以创建一种可以自己解析的格式。希望这能回答您的问题……当我的域对象模型开始变得复杂时,我更进一步并创建了我专门在SpecFlow场景中使用的“测试模型”。测试模型应该:让我们以博客为例。SpecFlow场景:创建博客帖子考虑编写以下场景,这样任何熟悉博客工作方式的人都知道发生了什么:场景:创建博客帖子给定一个名为“TestingwithSpecFlow”的博客存在SpecFlow"具有以下属性的博客:|领域|价值||标题|复杂模型||正文|这并不难。||状态|工作草案|那么“使用SpecFlow进行测试”博客中的帖子应该具有以下属性:|领域|价值||标题|复杂模型||正文|这并不难。||状态|工作草案|这模拟了一个博客有很多博文的复杂关系。域模型这个博客应用程序的域模型是:publicclassBlog{publicstringName{get;放;}公共字符串描述{得到;放;}publicIListPosts{get;私有集;}publicBlog(){Posts}}publicclassBlogPost{publicstringTitle{get;放;}publicstringBody{得到;放;}公共BlogPostStatus状态{得到;放;公共日期时间?发布日期{得到;放;}公共博客博客{得到;私有集;}publicBlogPost(Blogblog){Blog=blog;}}publicenumBlogPostStatus{WorkingDraft=0,Published=1,Unpublished=2,Deleted=3}请注意,我们的场景具有值为“WorkingDraft”的“Status”,但BlogPostStatus枚举具有WorkingDraft。你如何将这种“自然语言”状态翻译成枚举?现在进入测试模型。测试模型:BlogPostRowBlogPostRow类用于执行以下操作:将SpecFlow表转换为对象使用给定值更新域模型提供“复制构造函数”,它使用现有域模型实例中的值来播种BlogPostRow对象,}publicstringBody{得到;放;公共日期时间?发布日期{得到;放;}公共字符串状态{得到;放;}publicBlogPostRow(){}publicBlogPostRow(BlogPostpost){Title=post.Title;正文=post.Body;PublishDate=post.PublishDate;Status=GetStatusText(post.Status);}publicBlogPostCreateInstance(stringblogName,IDbContextctx){Blogblog=ctx.Blogs.Where(b=>b.Name==blogName).Single();BlogPostpost=newBlogPost(blog){Title=Title,Body=Body,PublishDate=PublishDate,Status=GetStatus(Status)};blog.Posts.Add(发布);回邮;}privateBlogPostStatusGetStatus(stringstatusText){BlogPostStatus状态;foreach(Enum.GetNames(typeof(BlogPostStatus))中的字符串名称){stringenumName=name.Replace("",string.Empty);如果(Enum.TryParse(enumName,outstatus))返回状态;}thrownewArgumentException("UnknownBlogPostStatusText:"+statusText);}privatestringGetStatusText(BlogPostStatusstatus){switch(status){caseBlogPostStatus.WorkingDraft:return"WorkingDraft";默认值:返回status.ToString();它在私有的GetStatus和GetStatusText中,其中人类可读的博客帖子状态值被转换为枚举,反之亦然(披露:我知道枚举不是最复杂的情??况,但它是一个容易理解的)最后一块难题是步骤定义。在步骤定义中使用测试模型和域模型步骤:给定一个名为“TestingwithSpecFlow”的博客存在定义:[Given(@"aBlognamed""(.*)""exists")]publicvoidGivenABlogNamedExists(stringblogName){使用(IDbContextctx=newTestContext()){Blogblog=newBlog(){Name=blogName};ctx.Blogs.Add(博客);ctx.SaveChanges();}}步骤:当我在“TestingwithSpecFlow”博客中创建具有以下属性的帖子时:|领域|价值||标题|复杂模型||正文|这并不难。||状态|工作草案|定义:[When(@"我在博客中创建了一个具有以下属性的帖子:")]publicvoidWhenICreateAPostInTheBlogWithTheFollowingAttributes(stringblogName,Tabletable){using(IDbContextctx=newTestContext()){BlogPostRowrow=table.CreateInstance();BlogPostpost=row.CreateInstance(blogName,ctx);ctx.BlogPosts.Add(帖子);ctx.SaveChanges();}}步骤:那么“TestingwithSpecFlow”博客中的一篇文章应该具有以下属性伊布特斯:|领域|价值||标题|复杂模型||正文|这并不难。||状态|工作草案|定义:[Then(@""(.*)""博客中的帖子应具有以下属性:")]publicvoidThenAPostInTheBlogShouldExistWithTheFollowingAttributes(stringblogName,Tabletable){using(IDbContextctx=newTestContext()){博客blog=ctx.Blogs.Where(b=>b.Name==blogName).Single();foreach(BlogPostpostinblog.Posts){BlogPostRowactual=newBlogPostRow(post);table.CompareToInstance(实际);}}}(TestContext-某种持久性数据存储,其生命周期为当前场景)更大上下文中的模型退一步说,“模型”这个词变得更加复杂,我们刚刚介绍了另一个模型让我们看看它们如何一起玩:你可以几乎可以将测试模型视为SpecFlow测试模型的视图,“视图”是用Gherkin编写的场景。我现在已经为几个存在与您在此处描述的相同问题的组织工作。这是促使我(尝试)开始写一本关于这个主题的书的原因之一。http://specflowcookbook.com/chapters/linking-table-rows/在这里我建议一个约定,允许你使用一个specflow表头来指示链接项来自哪里,如何识别你想要的,然后使用该行的内容为“查找”外部表提供数据。例如:场景:给圣诞老人的信出现在电子邮件发件箱中给定以下“孩子”存在|名字|姓|年龄||诺亚|史密斯|6||奥利弗|汤普森|3|并且存在以下“礼物”|来自孩子的孩子|类型|颜色||姓史密斯|乐高套装|||姓汤普森|机器人|红色||姓汤普森|自行车|蓝色|希望这可以帮助。一个好主意是在StepArgumentTransformation方法中重用标准MVCModelBinder的命名约定模式。这是一个示例:没有mvc是否可以进行模型绑定?这是代码的一部分(只是主要思想,没有任何验证和您的其他要求):功能:然后模型有效:|编号|儿童[0].Id|儿童[0].姓名|儿童[0].长度|儿童[1].Id|儿童[1].姓名|儿童[1].长度||1|222|姓名0|5|223|姓名1|6|步骤:[Then]publicvoidThen_Model_Is_Valid(MyObjectmyObject){//在这里使用你的绑定对象}[StepArgumentTransformation]publicMyObjectMyObjectTransform(Tabletable){varmodelState=newModelStateDictionary();varmodel=newMyObject();varstate=TryUpdateModel(model,table.Rows[0].ToDictionary(pair=>pair.Key,pair=>pair.Value),modelState);返回模型;这个对我有用。当然,您必须引用System.Web.Mvc库。使用TechTalk.SpecFlow.Assist;https://github.com/techtalk/SpecFlow/wiki/SpecFlow-Assist-Helpers以上是C#学习教程:SpecFlow和复杂对象分享的所有内容,如果对大家有用需要进一步了解C#学习教程,希望大家多多关注——[Given(@"resourceis")]publicvoidGiven_Resource_Is(Tablepayload){AddToScenarioContext("payload",payload.C??reateInstance());}本文来自网络收集,不代表立场,如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: