Asp.net WebAPI 单元测试

来源:互联网 发布:金蝶kis mac版 编辑:程序博客网 时间:2024/05/17 03:24

现在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试用

下载

0 1