【问题标题】:(headless) integration testing frameworks for asp.net mvc/webapi 5 [closed]用于 asp.net mvc/webapi 5 的(无头)集成测试框架 [关闭]
【发布时间】:2014-09-21 21:23:20
【问题描述】:

我目前正在研究 asp.net mvc 5 的(最好是无头的)集成测试框架(可能在同一个项目中使用 webapi)。我知道这 2 个:

还有其他的吗?我对任何与 specflow 配合得很好的框架都特别感兴趣。

【问题讨论】:

  • 有人能解释一下投反对票的原因吗?
  • 您收到的反对票很可能是因为这是一个只能根据人们自己的意见/经验(无论好坏)来回答的问题。这更像是一个具体的问答网站。为了记录,我和你有同样的问题。但是,对于 StackOverflow 来说,这并不是最好的问题。 HTH。
  • 这是一个具体的问题,可能对其他人有用。我没有征求任何意见。不知道现在 SO 上的人有什么问题。
  • 我所说的具体 的意思是,问题必须得到答案,而不仅仅是个人偏好或意见。应该有明确的答案。例如,谁能诚实地说 SpecsFor.Mvc 肯定比 MvcIntegartionTestFramework 更好?不,这取决于您的情况、开发人员、技能组合、要求——基本上,很多非确定性因素。我没有对你投反对票,因为我有同样的问题——但我理解为什么其他人可能会有。我希望这对未来的问题有所帮助。
  • 与手头的问题更相关的是,SpecsFor.Mvc 有点不成熟。这是一个小图书馆。不要误会我的意思,它实际上很酷。而且,如果您想在 UI/页面级别对断言进行集成测试等等,那是一种方法;然而,它不会让你进入ViewContext 或其他 MVC 上下文——它是“高级”的。 OTOH 的 MvcIntegrationTestFramework 比原始 UI 级别略低——基本上,在控制器只是通过线路将其信息返回给浏览器的级别。所以我想这真的取决于你想测试什么。

标签: asp.net-mvc asp.net-web-api asp.net-mvc-5 integration-testing specflow


【解决方案1】:

我今天成功地将 SpecsFor.Mvc 与 SpecFlow 集成。挺好看的。

这里有一组类可以帮助您开始将 SpecsFor.Mvc 与 SpecFlow 集成。当然,这些可以更好地抽象和扩展;但至少,这就是你所需要的:

namespace SpecsForMvc.SpecFlowIntegration
{
    using Microsoft.VisualStudio.TestingTools.UnitTesting;
    using SpecsFor.Mvc;
    using TechTalk.SpecFlow;

    [Binding]
    public class SpecsForMvcSpecFlowHooks
    {
        private static SpecsForIntegrationHost integrationHost;

        /// <summary>
        /// <p>
        /// This hook runs at the end of the entire test run.
        /// It's analogous to an MSTest method decorated with the
        /// <see cref="Microsoft.VisualStudio.TestingTools.UnitTesting.AssemblyCleanupAttribute" />
        /// attribute.
        /// </p>
        /// <p>
        /// NOTE: Not all test runners have the notion of a test run cleanup.
        /// If using MSTest, this probably gets run in a method decorated with
        /// the attribute mentioned above. For other test runners, this method
        /// may not execute until the test DLL is unloaded. YMMV.
        /// </p>
        /// </summary>
        [AfterTestRun]
        public void CleanUpTestRun()
        {
            integrationHost.Shutdown();
        }

        /// <summary>
        /// <p>
        /// This hook runs at the beginning of an entire test run.
        /// It's equivalent to an MSTest method decorated with the
        /// <see cref="Microsoft.VisualStudio.TestTools.UnitTesting.AssemblyInitializeAttribute />
        /// attribute.
        /// </p>
        /// <p>
        /// NOTE: Not all test runners have a notion of an assembly
        /// initializer or test run initializer, YMMV.
        /// </p>
        /// </summary>
        [BeforeTestRun]
        public static void InitializeTestRun()
        {
            var config = new SpecsForMvcConfig();

            config.UseIISExpress()
                .With(Project.Named("Your Project Name Here"))
                .ApplyWebConfigTransformForConfig("Debug");

            config.BuildRoutesUsing(r => RouteConfig.RegisterRoutes(r));

            // If you want to be authenticated for each request, 
            // implement IHandleAuthentication
            config.AuthenticateBeforeEachTestUsing<SampleAuthenticator>();

            // I originally tried to use Chrome, but the Selenium 
            // Chrome WebDriver, but it must be out of date because 
            // Chrome gave me an error and the tests didn't run (NOTE: 
            // I used the latest Selenium NuGet package as of
            // 23-08-2014). However, Firefox worked fine, so I used that.
            config.UseBrowser(BrowserDriver.Firefox);

            integrationHost = new SpecsForMvcIntegrationHost(config);
            integrationHost.Start();
        }

        /// <summary>
        /// This hook runs once before any of the SpecFlow feature's
        /// scenarios are run and stores a <see cref="SpecsFor.Mvc.MvcWebApp />
        /// instance in the <see cref="TechTalk.SpecFlow.FeatureContext" />
        /// for the feature.
        /// </summary>
        [BeforeFeature]
        public static void CreateFeatureMvcWebApp()
        {
            MvcWebApp theApp;
            if (!FeatureContext.Current.TryGetValue<MvcWebApp>(out theApp))
                FeatureContext.Current.Set<MvcWebApp>(new MvcWebApp());
        }
    }

    public class SpecsForMvcStepDefinitionBase
    {
        /// <summary>
        /// Gets the instance of the <see cref="SpecsFor.Mvc.MvcWebApp" />
        /// object stored in the <see cref="TechTalk.SpecFlow.FeatureContext" />
        /// for the current feature.
        /// </summary>
        public static MvcWebApp WebApp
        {
            get { return FeatureContext.Current.Get<MvcWebApp>(); }
        }
    }
}

然后,假设您有一个 SpecFlow 功能文件,如下所示(这是一个部分文件):

Feature: Login
    As a user of the website
    I want to be able to log on the the site
    in order to use the features available to site members.

# For the site I'm currently working with, even though it's MVC, it's more
# of a WebAPI before there was WebAPI--so the controllers accept JSON and return
# JsonResult objects--so that's what you're going to see.
Scenario: Using a valid username and password logs me on to the site
    Given the valid username 'somebody@somewhere.com'
    And the password 'my_super_secure_password'
    When the username and password are submitted to the login form
    Then the website will return a result
    And it will contain an authentication token
    And it will not contain any exception record.

现在是上述场景的步骤:

using Newtonsoft.Json;
using OpenQA.Selenium;
using MyWebSite.Controllers;
using Should;
using TechTalk.SpecFlow;

[Binding]
public class LoginSteps : SpecsForMvcStepDefinitionBase
{
    // The base class gets me the WebApp property that allows easy
    // access to the SpecsFor.Mvc.MvcWebApp object that drives a web browser
    // via Selenium.

    private string _username;
    private string _password;
    private string _portalSessionId;
    private ServiceResponse<LoginSummary> _loginResponse;

    [Given(@"the valid username '(.*)'")]
    [Given(@"the invalid username '(.*)'")]
    public void GivenAUsername(string username)
    {
        _username = username;
    }

    [Given(@"the valid password '(.*)'")]
    [Given(@"the invalid password '(.*)'")]
    public void GivenAPassword(string password)
    {
        _password = password;
    }

    [When(@"the username and password are submitted to the " +
          @"LoginUser action method of the UserController")]
    public void WhenTheUsernameAndPasswordAreSubmitted()
    {
        WebApp.NavigateTo<UserController>(
            c => c.LoginUser(_username, _password)
        );
    }

    [Then(@"the UserController will reply with a LoginSummary")]
    public void ThenTheUserControllerWillReplyWithALoginSummary()
    {
        _loginResponse = 
            JsonConvert.DeserializeObject<ServiceResponse<LoginSummary>>(
                WebApp.Browser.FindElement(By.TagName("pre")).Text
        );
    }

    [Then(@"it will contain an authentication token")]
    public void ThenItWillContainAnAuthenticationToken()
    {
        _loginSummary.Results.Count.ShouldBeGreaterThan(0);
        _loginSummary.Results[0].AuthenticationToken.ShouldNotBeEmpty();
    }

    [Then(@"it will not contain an exception record")]
    public void THenItWillNotContainAnExceptionRecord()
    {
        _loginSummary.Exception.ShouldBeNull();
    }
}

很酷。

关于用BeforeTestRunAfterTestRun修饰的方法,我在下面的博文中找到了代码cmets中提到的信息:Advanced SpecFlow: Using Hooks to Run Additional Automation Code

当然,如果您要测试演示文稿布局,您可能仍希望构建遵循页面对象模式的类。正如我在代码 cmets 中所述,我正在为之前的 WebAPI 编写集成测试但功能类似于 WebAPI 但使用 ASP.Net MVC 的特定应用程序。我们只是还没有正式将它移植到 WebAPI。

【讨论】:

    猜你喜欢
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    • 2010-10-21
    相关资源
    最近更新 更多