真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

ASP.NETWebAPI單元測試-單元測試-創(chuàng)新互聯(lián)

今天來到了最后的壓軸章節(jié):單元測試

浙江ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!

我們已經(jīng)有了完整的程序結(jié)構(gòu),現(xiàn)在是時候來對我們的組件做單元測試了。

在UnitTestingWebAPI.Tests類庫上添加UnitTestingWebAPI.Domain, UnitTestingWebAPI.Data, UnitTestingWebAPI.Service和UnitTestingWebAPI.API.Core 同樣要安裝下列的Nuget 包:

  1. Entity Framework

  2. Microsoft.AspNet.WebApi.Core

  3. Microsoft.AspNet.WebApi.Client

  4. Microsoft.AspNet.WebApi.Owin

  5. Microsoft.AspNet.WebApi.SelfHost

  6. Micoroft.Owin

  7. Owin

  8. Micoroft.Owin.Hosting

  9. Micoroft.Owin.Host.HttpListener

  10. Autofac.WebApi2

  11. NUnit

  12. NUnitTestAdapter

從清單中可知,我們將用NUnit 來寫單元測試

Services 單元測試


寫單元測試的第一件事是需要去設(shè)置或初始化一些單元測試中要用到的變量,NUnit框架則給要測試的方法添加Setup特性,在任何其他的NUnit測試開始之前,這一方法會先執(zhí)行,把Services層注入到Controller的構(gòu)造函數(shù)之后的第一件事就是進(jìn)行單元測試。因此在對WebAPI進(jìn)行單元測試之前需要仿造Repositories和Service。

在這個例子中會看到如何仿造ArticleService, 并在這個Service的構(gòu)造函數(shù)中注入IArticleRepository和IUnitOfWork,所以我們需要創(chuàng)建兩個"特別的"實例來注入。

ArticleService Constructor

private readonly IArticleRepository articlesRepository;
private readonly IUnitOfWork unitOfWork;

public ArticleService(IArticleRepository articlesRepository, IUnitOfWork unitOfWork)
{
    this.articlesRepository = articlesRepository;
    this.unitOfWork = unitOfWork;
}

這里的"特別的",是因為這些實例不是真正訪問數(shù)據(jù)庫的實例.

注意

單元測試必須運(yùn)行在內(nèi)存中并且不應(yīng)該訪問數(shù)據(jù)庫. 所有核心的方法必須通過像我們的例子中用Mock這樣的框架仿造。這個方式自動的測試會更快些。單元測試最基本的目的是更多的測試組件的行為,而不是真正的結(jié)果.

開始測試ArticleService,創(chuàng)建一個ServiceTests的文件并添加下列代碼:

[TestFixture]
public class ServicesTests
{
    #region Variables
    IArticleService _articleService;
    IArticleRepository _articleRepository;
    IUnitOfWork _unitOfWork;
    List
 _randomArticles;     #endregion       #region Setup     [SetUp]     public void Setup()     {         _randomArticles = SetupArticles();           _articleRepository = SetupArticleRepository();         _unitOfWork = new Mock().Object;         _articleService = new ArticleService(_articleRepository, _unitOfWork);     }       public List
 SetupArticles()     {         int _counter = new int();         List
 _articles = BloggerInitializer.GetAllArticles();           foreach (Article _article in _articles)             _article.ID = ++_counter;           return _articles;     }     public IArticleRepository SetupArticleRepository()     {         // Init repository         var repo = new Mock();         // Setup mocking behavior         repo.Setup(r => r.GetAll()).Returns(_randomArticles);         repo.Setup(r => r.GetById(It.IsAny()))             .Returns(new Func(                 id => _randomArticles.Find(a => a.ID.Equals(id))));         repo.Setup(r => r.Add(It.IsAny
()))             .Callback(new Action
(newArticle =>             {                 dynamic maxArticleID = _randomArticles.Last().ID;                 newArticle.ID = maxArticleID + 1;                 newArticle.DateCreated = DateTime.Now;                 _randomArticles.Add(newArticle);             }));         repo.Setup(r => r.Update(It.IsAny
()))             .Callback(new Action
(x =>             {                 var oldArticle = _randomArticles.Find(a => a.ID == x.ID);                 oldArticle.DateEdited = DateTime.Now;                 oldArticle = x;             }));         repo.Setup(r => r.Delete(It.IsAny
()))             .Callback(new Action
(x =>             {                 var _articleToRemove = _randomArticles.Find(a => a.ID == x.ID);                 if (_articleToRemove != null)                     _randomArticles.Remove(_articleToRemove);             }));         // Return mock implementation         return repo.Object;     }       #endregion }

如果你直接copy代碼可能會報錯:

One or more types required to compile a dynaic expression ....

ASP.NET Web API 單元測試 - 單元測試解決辦法:

在Assembiles中添加Microsoft.CSharp.dll

ASP.NET Web API 單元測試 - 單元測試

在SetupArticleRepository()方法中我們模仿了_articleRepository的行為,換句話說,當(dāng)一個特定的方法使用了這個Reporistory的實例,就會得到我們所期待的結(jié)果。然后我們在_articleService的構(gòu)造函數(shù)中注入這個實例。我們用下面代碼測試_articleService.GetArticles()的行為是否是我們所期待的.

ServiceShouldReturnAllArticles Test

[Test]
public void ServiceShouldReturnAllArticles()
{
    var articles = _articleService.GetArticles();

    NUnit.Framework.Assert.That(articles, Is.EqualTo(_randomArticles));
}

編譯項目,運(yùn)行測試,要確保這個測試變?yōu)榫G色通過狀態(tài),用同樣的方式創(chuàng)建下面的測試:

Services Test

[Test]
public void ServiceShouldReturnRightArticle()
{
    var wcfSecurityArticle = _articleService.GetArticle(2);

    NUnit.Framework.Assert.That(wcfSecurityArticle,
        Is.EqualTo(_randomArticles.Find(a => a.Title.Contains("Secure WCF Services"))));
}

[Test]
public void ServiceShouldAddNewArticle()
{
    var _newArticle = new Article()
    {
        Author = "Chris Sakellarios",
        Contents = "If you are an ASP.NET MVC developer, you will certainly..",
        Title = "URL Rooting in ASP.NET (Web Forms)",
        URL = "https://chsakell.com/2013/12/15/url-rooting-in-asp-net-web-forms/"
    };

    int _maxArticleIDBeforeAdd = _randomArticles.Max(a => a.ID);
    _articleService.CreateArticle(_newArticle);

    NUnit.Framework.Assert.That(_newArticle, Is.EqualTo(_randomArticles.Last()));
    NUnit.Framework.Assert.That(_maxArticleIDBeforeAdd + 1, Is.EqualTo(_randomArticles.Last().ID));
}

[Test]
public void ServiceShouldUpdateArticle()
{
    var _firstArticle = _randomArticles.First();

    _firstArticle.Title = "OData feat. ASP.NET Web API"; // reversed
    _firstArticle.URL = "http://t.co/fuIbNoc7Zh"; // short link
    _articleService.UpdateArticle(_firstArticle);

    NUnit.Framework.Assert.That(_firstArticle.DateEdited, Is.Not.EqualTo(DateTime.MinValue));
    NUnit.Framework.Assert.That(_firstArticle.URL, Is.EqualTo("http://t.co/fuIbNoc7Zh"));
    NUnit.Framework.Assert.That(_firstArticle.ID, Is.EqualTo(1)); // hasn't changed
}

[Test]
public void ServiceShouldDeleteArticle()
{
    int maxID = _randomArticles.Max(a => a.ID); // Before removal
    var _lastArticle = _randomArticles.Last();

    // Remove last article
    _articleService.DeleteArticle(_lastArticle);

    NUnit.Framework.Assert.That(maxID, Is.GreaterThan(_randomArticles.Max(a => a.ID))); // Max reduced by 1
}

WebAPI 控制器單元測試

在熟悉了偽造Services行為測試的基礎(chǔ)上,來進(jìn)行WebAPI控制器的單元測試。

第一件事:設(shè)置在測試中需要的變量。

用下面的代碼創(chuàng)建用于測試的控制器:

    [TestFixture]
    public class ControllerTests
    {
        #region Variables
        IArticleService _articleService;
        IArticleRepository _articleRepository;
        IUnitOfWork _unitOfWork;
        List
 _randomArticles;         #endregion         #region Setup         [SetUp]         public void Setup()         {             _randomArticles = SetupArticles();             _articleRepository = SetupArticleRepository();             _unitOfWork = new Mock().Object;             _articleService = new ArticleService(_articleRepository, _unitOfWork);         }         ///          /// Setup Articles         ///          ///          public List
 SetupArticles()         {             int _counter = new int();             List
 _articles = BloggerInitializer.GetAllArticles();             foreach (Article _article in _articles)                 _article.ID = ++_counter;             return _articles;         }         ///          /// Emulate _articleRepository behavior         ///          ///          public IArticleRepository SetupArticleRepository()         {             // Init repository             var repo = new Mock();             // Get all articles             repo.Setup(r => r.GetAll()).Returns(_randomArticles);             // Get Article by id             repo.Setup(r => r.GetById(It.IsAny()))                 .Returns(new Func(                     id => _randomArticles.Find(a => a.ID.Equals(id))));             // Add Article             repo.Setup(r => r.Add(It.IsAny
()))                 .Callback(new Action
(newArticle =>                 {                     dynamic maxArticleID = _randomArticles.Last().ID;                     newArticle.ID = maxArticleID + 1;                     newArticle.DateCreated = DateTime.Now;                     _randomArticles.Add(newArticle);                 }));             // Update Article             repo.Setup(r => r.Update(It.IsAny
()))                 .Callback(new Action
(x =>                 {                     var oldArticle = _randomArticles.Find(a => a.ID == x.ID);                     oldArticle.DateEdited = DateTime.Now;                     oldArticle.URL = x.URL;                     oldArticle.Title = x.Title;                     oldArticle.Contents = x.Contents;                     oldArticle.BlogID = x.BlogID;                 }));             // Delete Article             repo.Setup(r => r.Delete(It.IsAny
()))                 .Callback(new Action
(x =>                 {                     var _articleToRemove = _randomArticles.Find(a => a.ID == x.ID);                     if (_articleToRemove != null)                         _randomArticles.Remove(_articleToRemove);                 }));             // Return mock implementation             return repo.Object;         }         #endregion     }

控制器的類和其它的類一樣,所以我們可以分開各自測試。下面測試_articlesController.GetArticles(),看看是否能返回所有的文章。

[Test]
public void ControlerShouldReturnAllArticles()
{
    var _articlesController = new ArticlesController(_articleService);

    var result = _articlesController.GetArticles();

    CollectionAssert.AreEqual(result, _randomArticles);
}

請確保測試已綠色通過,我們初始化了3條數(shù)據(jù),用_articlesController.GetArticle(3)測試看看能否返回最后一條。

[Test]
public void ControlerShouldReturnLastArticle()
{
    var _articlesController = new ArticlesController(_articleService);

    var result = _articlesController.GetArticle(3) as OkNegotiatedContentResult
;     Assert.IsNotNull(result);     Assert.AreEqual(result.Content.Title, _randomArticles.Last().Title); }

測試一個無效的Update操作,必須失敗并且返回一個BadRequestResult, 重新調(diào)用設(shè)置在_articleRepository上的Update操作。

repo.Setup(r => r.Update(It.IsAny
()))     .Callback(new Action
(x =>     {         var oldArticle = _randomArticles.Find(a => a.ID == x.ID);         oldArticle.DateEdited = DateTime.Now;         oldArticle.URL = x.URL;         oldArticle.Title = x.Title;         oldArticle.Contents = x.Contents;         oldArticle.BlogID = x.BlogID;     }));

所以,當(dāng)我們測試一個不存在的文章就應(yīng)該返回失敗信息。

[Test]
public void ControlerShouldPutReturnBadRequestResult()
{
    var _articlesController = new ArticlesController(_articleService)
    {
        Configuration = new HttpConfiguration(),
        Request = new HttpRequestMessage
        {
            Method = HttpMethod.Put,
            RequestUri = new Uri("http://localhost/api/articles/-1")
        }
    };

    var badresult = _articlesController.PutArticle(-1, new Article() { Title = "Unknown Article" });
    Assert.That(badresult, Is.TypeOf());
}

通過分別成功更新第一篇文章、發(fā)表一篇新文章、發(fā)布失敗一篇文章來完成我們的單元測試。

Controller 單元測試

[Test]
public void ControlerShouldPutUpdateFirstArticle()
{
    var _articlesController = new ArticlesController(_articleService)
    {
        Configuration = new HttpConfiguration(),
        Request = new HttpRequestMessage
        {
            Method = HttpMethod.Put,
            RequestUri = new Uri("http://localhost/api/articles/1")
        }
    };

    IHttpActionResult updateResult = _articlesController.PutArticle(1, new Article()
    {
        ID = 1,
        Title = "ASP.NET Web API feat. OData",
        URL = "http://t.co/fuIbNoc7Zh",
        Contents = @"OData is an open standard protocol.."
    }) as IHttpActionResult;

    Assert.That(updateResult, Is.TypeOf());

    StatusCodeResult statusCodeResult = updateResult as StatusCodeResult;

    Assert.That(statusCodeResult.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));

    Assert.That(_randomArticles.First().URL, Is.EqualTo("http://t.co/fuIbNoc7Zh"));
}

[Test]
public void ControlerShouldPostNewArticle()
{
    var article = new Article
    {
        Title = "Web API Unit Testing",
        URL = "https://chsakell.com/web-api-unit-testing",
        Author = "Chris Sakellarios",
        DateCreated = DateTime.Now,
        Contents = "Unit testing Web API.."
    };

    var _articlesController = new ArticlesController(_articleService)
    {
        Configuration = new HttpConfiguration(),
        Request = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri("http://localhost/api/articles")
        }
    };

    _articlesController.Configuration.MapHttpAttributeRoutes();
    _articlesController.Configuration.EnsureInitialized();
    _articlesController.RequestContext.RouteData = new HttpRouteData(
    new HttpRoute(), new HttpRouteValueDictionary { { "_articlesController", "Articles" } });
    var result = _articlesController.PostArticle(article) as CreatedAtRouteNegotiatedContentResult
;     Assert.That(result.RouteName, Is.EqualTo("DefaultApi"));     Assert.That(result.Content.ID, Is.EqualTo(result.RouteValues["id"]));     Assert.That(result.Content.ID, Is.EqualTo(_randomArticles.Max(a => a.ID))); } [Test] public void ControlerShouldNotPostNewArticle() {     var article = new Article     {         Title = "Web API Unit Testing",         URL = "https://chsakell.com/web-api-unit-testing",         Author = "Chris Sakellarios",         DateCreated = DateTime.Now,         Contents = null     };     var _articlesController = new ArticlesController(_articleService)     {         Configuration = new HttpConfiguration(),         Request = new HttpRequestMessage         {             Method = HttpMethod.Post,             RequestUri = new Uri("http://localhost/api/articles")         }     };          _articlesController.Configuration.MapHttpAttributeRoutes();     _articlesController.Configuration.EnsureInitialized();     _articlesController.RequestContext.RouteData = new HttpRouteData(     new HttpRoute(), new HttpRouteValueDictionary { { "Controller", "Articles" } });     _articlesController.ModelState.AddModelError("Contents", "Contents is required field");     var result = _articlesController.PostArticle(article) as InvalidModelStateResult;     Assert.That(result.ModelState.Count, Is.EqualTo(1));     Assert.That(result.ModelState.IsValid, Is.EqualTo(false)); }

上面測試的重點,我們請求的幾個方面:返回碼或路由屬性。

管理 Handler單元測試

你可以通過創(chuàng)建HttpMessageInvoker的實例來測試Message Handler, 解析你要測試的Handler實例并調(diào)用SendAsync 方法。創(chuàng)建一個MessageHandlerTest.cs文件,并貼上下面的啟動設(shè)置代碼

#region Variables
private EndRequestHandler _endRequestHandler;
private HeaderAppenderHandler _headerAppenderHandler;
#endregion

#region Setup
[SetUp]
public void Setup()
{
    // Direct MessageHandler test
    _endRequestHandler = new EndRequestHandler();
    _headerAppenderHandler = new HeaderAppenderHandler()
    {
        InnerHandler = _endRequestHandler
    };
}
#endregion

我們在HeaderAppenderHandler的內(nèi)部設(shè)置另外一個可以終止請求的Hanlder.只要Uri中包含一個測試字符,從新調(diào)用EndRequestHandler將會終止請求.現(xiàn)在來測試.

[Test]
public async void ShouldAppendCustomHeader()
{
    var invoker = new HttpMessageInvoker(_headerAppenderHandler);
    var result = await invoker.SendAsync(new HttpRequestMessage(HttpMethod.Get,
        new Uri("http://localhost/api/test/")), CancellationToken.None);

    Assert.That(result.Headers.Contains("X-WebAPI-Header"), Is.True);
    Assert.That(result.Content.ReadAsStringAsync().Result,
        Is.EqualTo("Unit testing message handlers!"));
}

假如要做一個集成測試:當(dāng)一個請求被消息管道分配到Controller的Action的真實behavior。

這將需要運(yùn)行WebApi,然后運(yùn)行單元測試。怎么做呢?必須是 通過Self host的模式運(yùn)行API,然后設(shè)置恰當(dāng)?shù)呐渲谩?/p>

在UnitTestingWebAPI.Tests的項目中添加Startup.cs文件:

Hosting/Startup.cs

public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        var config = new HttpConfiguration();
        config.MessageHandlers.Add(new HeaderAppenderHandler());
        config.MessageHandlers.Add(new EndRequestHandler());
        config.Filters.Add(new ArticlesReversedFilter());
        config.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver());

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        config.MapHttpAttributeRoutes();

        // Autofac configuration
        var builder = new ContainerBuilder();
        builder.RegisterApiControllers(typeof(ArticlesController).Assembly);

        // Unit of Work
        var _unitOfWork = new Mock();
        builder.RegisterInstance(_unitOfWork.Object).As();

        //Repositories
        var _articlesRepository = new Mock();
        _articlesRepository.Setup(x => x.GetAll()).Returns(
                BloggerInitializer.GetAllArticles()
            );
        builder.RegisterInstance(_articlesRepository.Object).As();

        var _blogsRepository = new Mock();
        _blogsRepository.Setup(x => x.GetAll()).Returns(
            BloggerInitializer.GetBlogs
            );
        builder.RegisterInstance(_blogsRepository.Object).As();

        // Services
        builder.RegisterAssemblyTypes(typeof(ArticleService).Assembly)
            .Where(t => t.Name.EndsWith("Service"))
            .AsImplementedInterfaces().InstancePerRequest();

        builder.RegisterInstance(new ArticleService(_articlesRepository.Object, _unitOfWork.Object));
        builder.RegisterInstance(new BlogService(_blogsRepository.Object, _unitOfWork.Object));

        IContainer container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

        appBuilder.UseWebApi(config);
    }
}

可能注意到和UnitTestingWebAPI.API里的WebSetup類的不同之處在與,這里我們用了假的Repositories和Services。

返回到ControllerTests.cs中。

[Test]
public void ShouldCallToControllerActionAppendCustomHeader()
{
    //Arrange
    var address = "http://localhost:9000/";

    using (WebApp.Start(address))
    {
        HttpClient _client = new HttpClient();
        var response = _client.GetAsync(address + "api/articles").Result;

        Assert.That(response.Headers.Contains("X-WebAPI-Header"), Is.True);

        var _returnedArticles = response.Content.ReadAsAsync>().Result;
        Assert.That(_returnedArticles.Count, Is.EqualTo(BloggerInitializer.GetAllArticles().Count));
    }
}

媒體類型格式化器 測試

我們在UnitTestingWebAPI.API.Core中創(chuàng)建了ArticleFormatter,現(xiàn)在測試一下,應(yīng)該返回用逗號分割的文章字符串。它只能是寫文章的實例,但不能讀或者明白其它類型的類。為了應(yīng)用這個格式化器需要設(shè)置請求頭信息的Accept為application/article

[TestFixture]
public class MediaTypeFormatterTests
{
    #region Variables
    Blog _blog;
    Article _article;
    ArticleFormatter _formatter;
    #endregion

    #region Setup
    [SetUp]
    public void Setup()
    {
        _blog = BloggerInitializer.GetBlogs().First();
        _article = BloggerInitializer.GetChsakellsArticles().First();
        _formatter = new ArticleFormatter();
    }
    #endregion
}

我們可以創(chuàng)建一個ObjectContent來測試MediaTypeFormatter,傳遞一個對象來檢查是否能被被格式化,如果格式化器不能讀和寫傳遞過去的對象則會拋出異常,例如,文章的格式化器不能識別Blog對象:

[Test]
public void FormatterShouldThrowExceptionWhenUnsupportedType()
{
    Assert.Throws(() => new ObjectContent(_blog, _formatter));
}

換句話說,傳一個Article對象就一定會通過測試

[Test]
public void FormatterShouldNotThrowExceptionWhenArticle()
{
    Assert.DoesNotThrow(() => new ObjectContent
(_article, _formatter)); }

用下面的代碼測試不符合MediaType formatter的Media type

Media Type Formatters Unit tests

[Test]
public void FormatterShouldHeaderBeSetCorrectly()
{
    var content = new ObjectContent
(_article, new ArticleFormatter());     Assert.That(content.Headers.ContentType.MediaType, Is.EqualTo("application/article")); } [Test] public async void FormatterShouldBeAbleToDeserializeArticle() {     var content = new ObjectContent
(_article, _formatter);     var deserializedItem = await content.ReadAsAsync
(new[] { _formatter });     Assert.That(_article, Is.SameAs(deserializedItem)); } [Test] public void FormatterShouldNotBeAbleToWriteUnsupportedType() {     var canWriteBlog = _formatter.CanWriteType(typeof(Blog));     Assert.That(canWriteBlog, Is.False); } [Test] public void FormatterShouldBeAbleToWriteArticle() {     var canWriteArticle = _formatter.CanWriteType(typeof(Article));     Assert.That(canWriteArticle, Is.True); }

路由測試

在不Host Web API的情況下,測試路由配置。為了這個目的,需要一個可以從HttpControllerContext的實例中返回Controllerl類型或Controller中Action的幫助類,在測試之前,先創(chuàng)建一個路由配置的HttpConfiguration

Helpers/ControllerActionSelector.cs

public class ControllerActionSelector
{
    #region Variables
    HttpConfiguration config;
    HttpRequestMessage request;
    IHttpRouteData routeData;
    IHttpControllerSelector controllerSelector;
    HttpControllerContext controllerContext;
    #endregion

    #region Constructor
    public ControllerActionSelector(HttpConfiguration conf, HttpRequestMessage req)
    {
        config = conf;
        request = req;
        routeData = config.Routes.GetRouteData(request);
        request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;
        controllerSelector = new DefaultHttpControllerSelector(config);
        controllerContext = new HttpControllerContext(config, routeData, request);
    }
    #endregion

    #region Methods
    public string GetActionName()
    {
        if (controllerContext.ControllerDescriptor == null)
            GetControllerType();

        var actionSelector = new ApiControllerActionSelector();
        var descriptor = actionSelector.SelectAction(controllerContext);

        return descriptor.ActionName;
    }

    public Type GetControllerType()
    {
        var descriptor = controllerSelector.SelectController(request);
        controllerContext.ControllerDescriptor = descriptor;
        return descriptor.ControllerType;
    }
    #endregion
}

下面是路由測試:

[TestFixture]
public class RouteTests
{
    #region Variables
    HttpConfiguration _config;
    #endregion

    #region Setup
    [SetUp]
    public void Setup()
    {
        _config = new HttpConfiguration();
        _config.Routes.MapHttpRoute(name: "DefaultWebAPI", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional });
    }
    #endregion

    #region Helper methods
    public static string GetMethodName(Expression> expression)
    {
        var method = expression.Body as MethodCallExpression;
        if (method != null)
            return method.Method.Name;

        throw new ArgumentException("Expression is wrong");
    }
    #endregion
}

測試一個請求api/articles/5到ArticleController的action GetArticle(int id)

[Test]
public void RouteShouldControllerGetArticleIsInvoked()
{
    var request = new HttpRequestMessage(HttpMethod.Get, "http://www.chsakell.com/api/articles/5");

    var _actionSelector = new ControllerActionSelector(_config, request);

    Assert.That(typeof(ArticlesController), Is.EqualTo(_actionSelector.GetControllerType()));
    Assert.That(GetMethodName((ArticlesController c) => c.GetArticle(5)),
        Is.EqualTo(_actionSelector.GetActionName()));
}

我們用反射得到controller的action名稱,用同樣的方法來測試post提交的action

[Test]
public void RouteShouldPostArticleActionIsInvoked()
{
    var request = new HttpRequestMessage(HttpMethod.Post, "http://www.chsakell.com/api/articles/");

    var _actionSelector = new ControllerActionSelector(_config, request);

    Assert.That(GetMethodName((ArticlesController c) =>
        c.PostArticle(new Article())), Is.EqualTo(_actionSelector.GetActionName()));
}

下面這個測試,路由會發(fā)生異常.

[Test]
public void RouteShouldInvalidRouteThrowException()
{
    var request = new HttpRequestMessage(HttpMethod.Post, "http://www.chsakell.com/api/InvalidController/");

    var _actionSelector = new ControllerActionSelector(_config, request);

    Assert.Throws(() => _actionSelector.GetActionName());
}

結(jié)論

我們看到了Web API棧很多方面的單元測試,例如: mocking 服務(wù)層,單元測試控制器,消息管道,過濾器,定制媒體類型和路由配置。

嘗試在你的程序中總是寫單元測試,你不會后悔的。從里面會得到很多的好處,例如:在repository中一個簡單的修改可能破壞很多方面,如果寫一個合適的測試,則可能破壞你程序的問題會立即出現(xiàn).

原文:chsakell's Blog

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨有T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務(wù)器買多久送多久。


網(wǎng)站名稱:ASP.NETWebAPI單元測試-單元測試-創(chuàng)新互聯(lián)
文章URL:http://weahome.cn/article/ddoiog.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部