• Asp.net WebAPI 单元测试


    现在Asp.net webapi 运用的越来越多,其单元而是也越来越重要。一般软件开发都是多层结构,上层调用下层的接口,而各层的实现人员不同,一般大家都只写自己对应单元测试。对下层的依赖我们通过IOC来做。首先看我们的Controller定义及实现

     public class ArticlesController : ApiController
        {
            private IArticleService _articleService;
    
            public ArticlesController(IArticleService articleService)
            {
                _articleService = articleService;
            }
    
            // GET: api/Articles
            public IEnumerable<Article> GetArticles()
            {
                return _articleService.GetArticles();
            }
    
            // GET: api/Articles/5
            [ResponseType(typeof(Article))]
            public IHttpActionResult GetArticle(int id)
            {
                Article article = _articleService.GetArticle(id);
                if (article == null)
                {
                    return NotFound();
                }
    
                return Ok(article);
            }
    
            // PUT: api/Articles/5
            [ResponseType(typeof(void))]
            public IHttpActionResult PutArticle(int id, Article article)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                if (id != article.ID)
                {
                    return BadRequest();
                }
                try
                {
                    _articleService.UpdateArticle(article);
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!ArticleExists(id))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
    
                return StatusCode(HttpStatusCode.NoContent);
            }
    
            // POST: api/Articles
            [ResponseType(typeof(Article))]
            public IHttpActionResult PostArticle(Article article)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                _articleService.CreateArticle(article);
    
                return CreatedAtRoute("DefaultApi", new { id = article.ID }, article);
            }
    
            // DELETE: api/Articles/5
            [ResponseType(typeof(Article))]
            public IHttpActionResult DeleteArticle(int id)
            {
                Article article = _articleService.GetArticle(id);
                if (article == null)
                {
                    return NotFound();
                }
    
                _articleService.DeleteArticle(article);
    
                return Ok(article);
            }
    
            private bool ArticleExists(int id)
            {
                return _articleService.GetArticle(id) != null;
            }
        }

    首先构造函数 需要IArticleService实例,在Controller的action中将需要用到该service。【请千万不要告诉我说这里的controller非常简单,不需要做单元测试!在实际项目中有人为了不做Controller的单元测试,把里面的逻辑全部提取出来放在Helper里面,然后对Helper来做单元测试】

    IOC的实现:

    我这里用的是Unity, 所以首先需要安装Install-Package Unity.WebApi.5.1

      public class WebApiApplication : System.Web.HttpApplication
        {
            protected void Application_Start()
            {
                GlobalConfiguration.Configure(WebApiConfig.Register);
                //Install-Package Unity.WebApi.5.1
                IUnityContainer container = new UnityContainer()
                .RegisterType<IArticleService, ArticleService>()
                .RegisterType<IBlogService, BlogService>();
      
                //GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
                  GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new UnityHttpControllerActivator(container));
            }
        }
        public class UnityHttpControllerActivator : IHttpControllerActivator
        {
            public IUnityContainer UnityContainer { get; private set; }
            public UnityHttpControllerActivator(IUnityContainer unityContainer)
            {
                this.UnityContainer = unityContainer;
            }
    
            public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
            {
                return (IHttpController)this.UnityContainer.Resolve(controllerType);
            }
        }

    一般我们的controller都只用DependencyResolver和IHttpControllerActivator 来实现控制反转。

    单元测试我一般用Moq 和nunit ,所以需要 Install-Package Moq 和 Install-Package NUnit

    单元测试的code 如下:

      public void TestPostArticle()
            {
                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")
                    }
                };
                var result = _articlesController.PostArticle(article) as CreatedAtRouteNegotiatedContentResult<Article>;
    
                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)));
            }

    在controller的实例的时候直接传递IArticleService 实例。

      public static   IArticleService GetIArticleService()
            {
       
                var _article = new Mock<IArticleService>();
                _article.Setup(x => x.GetArticles(It.IsAny<string>())).Returns(new Func<string, List<Article>>(name =>
                {
                    if (string.IsNullOrEmpty(name))
                    {
                        return _randomArticles;
                    }
                    else
                    {
                        return _randomArticles.FindAll(x => x.Title.Contains(name));
                    }
    
                }));
                _article.Setup(x => x.GetArticle(It.IsAny<int>())).Returns(new Func<int, Article>(id =>
                {
                    return _randomArticles.Find(x => x.ID == id);
                }));
                _article.Setup(x => x.GetArticle(It.IsAny<string>())).Returns(new Func<string, Article>(name =>
                {
                    return _randomArticles.Find(x => x.Title == name);
                }));
                _article.Setup(r => r.CreateArticle(It.IsAny<Article>()))
                   .Callback(new Action<Article>(newArticle =>
                   {
                       newArticle.DateCreated = DateTime.Now;
                       newArticle.ID = _randomArticles.Last().ID + 1;
                       _randomArticles.Add(newArticle);
                   }));
    
                _article.Setup(r => r.UpdateArticle(It.IsAny<Article>()))
                    .Callback(new Action<Article>(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;
                    }));
                return _article.Object;
            }

    由于WebApi一般都是用来提供接口的,使用者往往是以发送http请求来获取数据,我们也可以用这种方式来做单元测试:

      public void TestPostArticle2()
            {
                var article = new Article
                {
                    Title = "Web API Unit Testing2",
                    URL = "https://chsakell.com/web-api-unit-testing",
                    Author = "Chris Sakellarios",
                    DateCreated = DateTime.Now,
                    Contents = "Unit testing Web API.."
                };
                var address = "http://localhost:9000/";
    
                using (WebApp.Start<Startup>(address))
                {
                    HttpClient _client = new HttpClient();
                    var response = _client.PostAsJsonAsync<Article>(address + "api/articles/", article).Result;
                    var result = response.Content.ReadAsAsync<Article>().Result;
                    Assert.That(result.Title, Is.EqualTo(article.Title));
                    Assert.That(_randomArticles.Last().Title, Is.EqualTo(article.Title));
                }
    
    
            }

    那么我们如何托起这个web 程序,有如何 使用IOC,

    这里IOC 用Autofac,其所用包如下:

    Install-Package Owin
    Install-Package Microsoft.AspNet.WebApi.Owin
    Install-Package Microsoft.Owin.Host.HttpListener
    Install-Package Microsoft.Owin.Hosting
    Install-Package Autofac
    Install-Package Autofac.WebApi2

     public class Startup
        {
            public void Configuration(IAppBuilder appBuilder)
            {
                var config = new HttpConfiguration();
               // config.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver());
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                var builder = new ContainerBuilder();
                builder.RegisterApiControllers(typeof(ArticlesController).Assembly);
    
                var _articleService = Helper.GetIArticleService();
                builder.RegisterInstance(_articleService).As<IArticleService>();
    
                
                IContainer container = builder.Build();
                config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    
                appBuilder.UseWebApi(config);
            }
        }

     参考:

    ASP.NET Web API Unit Testing

    Net 4.5中的HttpClient试用

    下载

  • 相关阅读:
    POJ 2155:Matrix 二维树状数组
    POJ 2823:Sliding Window 单调队列
    POJ 3007:Organize Your Train part II
    51nod 1208 && POJ 2482:Stars in Your Window
    POJ 3061:Subsequence 查找连续的几个数,使得这几个数的和大于给定的S
    51nod 1206:Picture 求覆盖周长
    POJ 1195:Mobile phones 二维树状数组
    lightoj 1319
    暴力大法好
    Poj1273--Drainage Ditches(最大流)
  • 原文地址:https://www.cnblogs.com/majiang/p/5424675.html
Copyright © 2020-2023  润新知