代码之家  ›  专栏  ›  技术社区  ›  Ed James

使用ASP.NET网站取消编辑

  •  4
  • Ed James  · 技术社区  · 16 年前

    我目前正在尝试升级我们的构建服务器,从没有构建服务器升级到有一个!

    我用的是JetBrains TeamCity (使用过 ReSharper 几年来,我相信他们的东西),并打算使用 NUnit MSBuild .

    但是,我提出了一个问题:似乎不可能用nunit测试ASP.NET网站。我曾假设可以在构建后将其配置为测试应用程序代码,但似乎唯一能够很好地进行测试的方法是将网站转换为Web应用程序(我的老板不喜欢这样的想法)。

    我该怎么办?

    请记住,测试需要能够从TeamCity自动启动。

    1 回复  |  直到 15 年前
        1
  •  8
  •   Peter Mortensen Pieter Jan Bonestroo    15 年前
    • 如果你想冒烟测试你的站点,或者在一些端点上砰的一声——请看下面的代码。

    • 另一方面,如果您想要测试不稳定(可检测)的ASP.NET网站程序集(而不是Web应用程序),那么您就是,正如他们在法国所说的,S.O.L.

    程序集是一个随机命名的动态编译程序集,位于框架临时ASP.NET文件的内部深处,使测试几乎不可能进行。

    您确实需要考虑以下几个选项:

    1. 将需要测试的逻辑放入单独的程序集中。
    2. 更改为交付可测试程序集的Web应用程序项目。

    对不起,我想你找不到你要找的,但我可能错了。让我们看看。

    祝你好运


    Download Visual Studio 2008 sample with site and applicatgion .

    我写了一个包装纸 WebHost.WebServer.dll 它是开发服务器的核心,在 CI . 我一直在用它。

    这里是一个缩小的版本,包括一个使用示例。

    测试.cs

    using System.Net;
    using NUnit.Framework;
    
    namespace Salient.Excerpts
    {
        [TestFixture]
        public class WebHostServerFixture : WebHostServer
        {
            [TestFixtureSetUp]
            public void TestFixtureSetUp()
            {
                // debug/bin/testproject/solution/siteundertest - make sense?
                StartServer(@"..\..\..\..\TestSite");
    
                // is the equivalent of
                // StartServer(@"..\..\..\..\TestSite",
                // GetAvailablePort(8000, 10000, IPAddress.Loopback, true), "/", "localhost");
            }
            [TestFixtureTearDown]
            public void TestFixtureTearDown()
            {
                StopServer();
            }
    
            [Test]
            public void Test()
            {
                // while a reference to the web app under test is not necessary,
                // if you do add a reference to this test project you may F5 debug your tests.
                // if you debug this test you will break in Default.aspx.cs
                string html = new WebClient().DownloadString(NormalizeUri("Default.aspx"));
            }
        }
    }
    

    Web主机服务器.cs

    // Project: Salient
    // http://salient.codeplex.com
    // Date: April 16 2010
    
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Threading;
    using Microsoft.VisualStudio.WebHost;
    
    namespace Salient.Excerpts
    {
        /// <summary>
        /// A general purpose Microsoft.VisualStudio.WebHost.Server test fixture.
        /// WebHost.Server is the core of the Visual Studio Development Server (WebDev.WebServer).
        ///
        /// This server is run in-process and may be used in F5 debugging.
        /// </summary>
        /// <remarks>
        /// If you are adding this source code to a new project, You will need to
        /// manually add a reference to WebDev.WebHost.dll to your project. It cannot
        /// be added from within Visual Studio.
        ///
        /// Please see the Readme.txt accompanying this code for details.
        /// </remarks>
        /// NOTE: code from various namespaces/classes in the Salient project have been merged into this
        /// single class for this post in the interest of brevity
        public class WebHostServer
        {
            private Server _server;
    
            public string ApplicationPath { get; private set; }
    
            public string HostName { get; private set; }
    
            public int Port { get; private set; }
    
            public string VirtualPath { get; private set; }
    
            public string RootUrl
            {
                get { return string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}{2}", HostName, Port, VirtualPath); }
            }
    
            /// <summary>
            /// Combine the RootUrl of the running web application with the relative url specified.
            /// </summary>
            public virtual Uri NormalizeUri(string relativeUrl)
            {
                return new Uri(RootUrl + relativeUrl);
            }
    
            /// <summary>
            /// Will start "localhost" on first available port in the range 8000-10000 with vpath "/"
            /// </summary>
            /// <param name="applicationPath"></param>
            public void StartServer(string applicationPath)
            {
                StartServer(applicationPath, GetAvailablePort(8000, 10000, IPAddress.Loopback, true), "/", "localhost");
            }
    
            /// <summary>
            /// </summary>
            /// <param name="applicationPath">Physical path to application.</param>
            /// <param name="port">Port to listen on.</param>
            /// <param name="virtualPath">Optional. defaults to "/"</param>
            /// <param name="hostName">Optional. Is used to construct RootUrl. Defaults to "localhost"</param>
            public void StartServer(string applicationPath, int port, string virtualPath, string hostName)
            {
                if (_server != null)
                {
                    throw new InvalidOperationException("Server already started");
                }
    
                // WebHost.Server will not run on any other IP
                IPAddress ipAddress = IPAddress.Loopback;
    
                if(!IsPortAvailable(ipAddress, port))
                {
                    throw new Exception(string.Format("Port {0} is in use.", port));
                }
    
                applicationPath = Path.GetFullPath(applicationPath);
    
                virtualPath = String.Format("/{0}/", (virtualPath ?? string.Empty).Trim('/')).Replace("//", "/");
    
                _server = new Server(port, virtualPath, applicationPath, false, false);
                _server.Start();
    
                ApplicationPath = applicationPath;
                Port = port;
                VirtualPath = virtualPath;
                HostName = string.IsNullOrEmpty(hostName) ? "localhost" : hostName;
            }
    
            /// <summary>
            /// Stops the server.
            /// </summary>
            public void StopServer()
            {
                if (_server != null)
                {
                    _server.Stop();
                    _server = null;
                    // allow some time to release the port
                    Thread.Sleep(100);
                }
            }
    
            public void Dispose()
            {
                StopServer();
            }
    
    
           /// <summary>
            /// Gently polls specified IP:Port to determine if it is available.
            /// </summary>
            /// <param name="ipAddress"></param>
            /// <param name="port"></param>
            public static bool IsPortAvailable(IPAddress ipAddress, int port)
            {
                bool portAvailable = false;
    
                for (int i = 0; i < 5; i++)
                {
                    portAvailable = GetAvailablePort(port, port, ipAddress, true) == port;
                    if (portAvailable)
                    {
                        break;
                    }
                    // be a little patient and wait for the port if necessary,
                    // the previous occupant may have just vacated
                    Thread.Sleep(100);
                }
                return portAvailable;
            }
    
            /// <summary>
            /// Returns first available port on the specified IP address.
            /// The port scan excludes ports that are open on ANY loopback adapter.
            ///
            /// If the address upon which a port is requested is an 'ANY' address all
            /// ports that are open on ANY IP are excluded.
            /// </summary>
            /// <param name="rangeStart"></param>
            /// <param name="rangeEnd"></param>
            /// <param name="ip">The IP address upon which to search for available port.</param>
            /// <param name="includeIdlePorts">If true includes ports in TIME_WAIT state in results.
            /// TIME_WAIT state is typically cool down period for recently released ports.</param>
            /// <returns></returns>
            public static int GetAvailablePort(int rangeStart, int rangeEnd, IPAddress ip, bool includeIdlePorts)
            {
                IPGlobalProperties ipProps = IPGlobalProperties.GetIPGlobalProperties();
    
                // if the ip we want a port on is an 'any' or loopback port we need to exclude all ports that are active on any IP
                Func<IPAddress, bool> isIpAnyOrLoopBack = i => IPAddress.Any.Equals(i) ||
                                                               IPAddress.IPv6Any.Equals(i) ||
                                                               IPAddress.Loopback.Equals(i) ||
                                                               IPAddress.IPv6Loopback.
                                                                   Equals(i);
                // get all active ports on specified IP.
                List<ushort> excludedPorts = new List<ushort>();
    
                // if a port is open on an 'any' or 'loopback' interface then include it in the excludedPorts
                excludedPorts.AddRange(from n in ipProps.GetActiveTcpConnections()
                                       where
                                           n.LocalEndPoint.Port >= rangeStart &&
                                           n.LocalEndPoint.Port <= rangeEnd && (
                                           isIpAnyOrLoopBack(ip) || n.LocalEndPoint.Address.Equals(ip) ||
                                            isIpAnyOrLoopBack(n.LocalEndPoint.Address)) &&
                                            (!includeIdlePorts || n.State != TcpState.TimeWait)
                                       select (ushort)n.LocalEndPoint.Port);
    
                excludedPorts.AddRange(from n in ipProps.GetActiveTcpListeners()
                                       where n.Port >= rangeStart && n.Port <= rangeEnd && (
                                       isIpAnyOrLoopBack(ip) || n.Address.Equals(ip) || isIpAnyOrLoopBack(n.Address))
                                       select (ushort)n.Port);
    
                excludedPorts.AddRange(from n in ipProps.GetActiveUdpListeners()
                                       where n.Port >= rangeStart && n.Port <= rangeEnd && (
                                       isIpAnyOrLoopBack(ip) || n.Address.Equals(ip) || isIpAnyOrLoopBack(n.Address))
                                       select (ushort)n.Port);
    
                excludedPorts.Sort();
    
                for (int port = rangeStart; port <= rangeEnd; port++)
                {
                    if (!excludedPorts.Contains((ushort)port))
                    {
                        return port;
                    }
                }
    
                return 0;
            }
        }
    }
    

    注:该 Microsoft.VisualStudio.WebHost 文件中包含命名空间 WebDev.WebHost.dll . 此文件位于GAC中,但无法从Visual Studio中添加对此程序集的引用。

    要添加引用,您需要在文本编辑器中打开.csproj文件并手动添加引用。

    寻找 ItemGroup 它包含项目引用并添加以下元素:

    <Reference Include="WebDev.WebHost, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=x86">
      <Private>False</Private>
    </Reference>
    

    参考文献: http://www.codeproject.com/KB/aspnet/test-with-vs-devserver-2.aspx