├── .gitattributes ├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── README.md ├── UnitTestingWebAPI.API.Core ├── App.config ├── Controllers │ ├── ArticlesController.cs │ └── BlogsController.cs ├── CustomAssembliesResolver.cs ├── Filters │ └── ArticlesReversedFilter.cs ├── MediaTypeFormatters │ └── ArticleFormatter.cs ├── MessageHandlers │ ├── EndRequestHandler.cs │ └── HeaderAppenderHandler.cs ├── Properties │ └── AssemblyInfo.cs ├── UnitTestingWebAPI.API.Core.csproj └── packages.config ├── UnitTestingWebAPI.API ├── Global.asax ├── Global.asax.cs ├── Properties │ └── AssemblyInfo.cs ├── Startup.cs ├── UnitTestingWebAPI.API.csproj ├── Web.Debug.config ├── Web.Release.config ├── Web.config └── packages.config ├── UnitTestingWebAPI.Data ├── App.config ├── BloggerEntities.cs ├── BloggerInitializer.cs ├── Configurations │ ├── ArticleConfiguration.cs │ └── BlogConfiguration.cs ├── Infrastructure │ ├── DbFactory.cs │ ├── Disposable.cs │ ├── IDbFactory.cs │ ├── IRepository.cs │ ├── IUnitOfWork.cs │ ├── RepositoryBase.cs │ └── UnitOfWork.cs ├── Properties │ └── AssemblyInfo.cs ├── Repositories │ ├── ArticleRepository.cs │ └── BlogRepository.cs ├── UnitTestingWebAPI.Data.csproj └── packages.config ├── UnitTestingWebAPI.Domain ├── Article.cs ├── Blog.cs ├── Properties │ └── AssemblyInfo.cs └── UnitTestingWebAPI.Domain.csproj ├── UnitTestingWebAPI.Service ├── ArticleService.cs ├── BlogService.cs ├── Properties │ └── AssemblyInfo.cs └── UnitTestingWebAPI.Service.csproj ├── UnitTestingWebAPI.Tests ├── ActionFilterTests.cs ├── App.config ├── ControllerTests.cs ├── Helpers │ └── ControllerActionSelector.cs ├── Hosting │ └── Startup.cs ├── MediaTypeFormatterTests.cs ├── MessageHandlerTests.cs ├── Properties │ └── AssemblyInfo.cs ├── RouteTests.cs ├── ServicesTests.cs ├── UnitTestingWebAPI.Tests.csproj └── packages.config ├── UnitTestingWebAPI.sln └── licence /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/webapiunittesting/3a049cc8b1fa63f4bf4226588682eea27b8f3a19/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config 41 | 42 | 43 | 44 | $(MSBuildProjectDirectory)\packages.config 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | $(NuGetToolsPath)\NuGet.exe 51 | @(PackageSource) 52 | 53 | "$(NuGetExePath)" 54 | mono --runtime=v4.0.30319 "$(NuGetExePath)" 55 | 56 | $(TargetDir.Trim('\\')) 57 | 58 | -RequireConsent 59 | -NonInteractive 60 | 61 | "$(SolutionDir) " 62 | "$(SolutionDir)" 63 | 64 | 65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 67 | 68 | 69 | 70 | RestorePackages; 71 | $(BuildDependsOn); 72 | 73 | 74 | 75 | 76 | $(BuildDependsOn); 77 | BuildPackage; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ASP.NET Web API Unit Testing 2 | 3 | [![License](https://img.shields.io/github/license/chsakell/webapiunittesting.svg)](https://github.com/chsakell/webapiunittesting/blob/master/licence) 4 | 5 | Blog post: ASP.NET Web API Unit Testing 6 | 7 |

Follow chsakell's Blog

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 28 | 29 | 30 |
FacebookTwitter
Microsoft Web Application Development
23 | facebook 24 | 26 | twitter-small 27 |
31 | 32 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/Controllers/ArticlesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity.Infrastructure; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Web.Http; 9 | using System.Web.Http.Description; 10 | using UnitTestingWebAPI.Domain; 11 | using UnitTestingWebAPI.Service; 12 | 13 | namespace UnitTestingWebAPI.API.Core.Controllers 14 | { 15 | public class ArticlesController : ApiController 16 | { 17 | private IArticleService _articleService; 18 | 19 | public ArticlesController(IArticleService articleService) 20 | { 21 | _articleService = articleService; 22 | } 23 | 24 | // GET: api/Articles 25 | public IEnumerable
GetArticles() 26 | { 27 | return _articleService.GetArticles(); 28 | } 29 | 30 | // GET: api/Articles/5 31 | [ResponseType(typeof(Article))] 32 | public IHttpActionResult GetArticle(int id) 33 | { 34 | Article article = _articleService.GetArticle(id); 35 | if (article == null) 36 | { 37 | return NotFound(); 38 | } 39 | 40 | return Ok(article); 41 | } 42 | 43 | // PUT: api/Articles/5 44 | [ResponseType(typeof(void))] 45 | public IHttpActionResult PutArticle(int id, Article article) 46 | { 47 | if (!ModelState.IsValid) 48 | { 49 | return BadRequest(ModelState); 50 | } 51 | 52 | if (id != article.ID) 53 | { 54 | return BadRequest(); 55 | } 56 | 57 | _articleService.UpdateArticle(article); 58 | 59 | try 60 | { 61 | _articleService.SaveArticle(); 62 | } 63 | catch (DbUpdateConcurrencyException) 64 | { 65 | if (!ArticleExists(id)) 66 | { 67 | return NotFound(); 68 | } 69 | else 70 | { 71 | throw; 72 | } 73 | } 74 | 75 | return StatusCode(HttpStatusCode.NoContent); 76 | } 77 | 78 | // POST: api/Articles 79 | [ResponseType(typeof(Article))] 80 | public IHttpActionResult PostArticle(Article article) 81 | { 82 | if (!ModelState.IsValid) 83 | { 84 | return BadRequest(ModelState); 85 | } 86 | 87 | _articleService.CreateArticle(article); 88 | 89 | return CreatedAtRoute("DefaultApi", new { id = article.ID }, article); 90 | } 91 | 92 | // DELETE: api/Articles/5 93 | [ResponseType(typeof(Article))] 94 | public IHttpActionResult DeleteArticle(int id) 95 | { 96 | Article article = _articleService.GetArticle(id); 97 | if (article == null) 98 | { 99 | return NotFound(); 100 | } 101 | 102 | _articleService.DeleteArticle(article); 103 | 104 | return Ok(article); 105 | } 106 | 107 | private bool ArticleExists(int id) 108 | { 109 | return _articleService.GetArticle(id) != null; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/Controllers/BlogsController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Data.Entity.Infrastructure; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Web.Http; 10 | using System.Web.Http.Description; 11 | using UnitTestingWebAPI.Domain; 12 | using UnitTestingWebAPI.Service; 13 | 14 | namespace UnitTestingWebAPI.API.Core.Controllers 15 | { 16 | public class BlogsController : ApiController 17 | { 18 | private IBlogService _blogService; 19 | 20 | public BlogsController(IBlogService blogService) 21 | { 22 | _blogService = blogService; 23 | } 24 | 25 | // GET: api/Blogs 26 | public IEnumerable GetBlogs() 27 | { 28 | return _blogService.GetBlogs(); 29 | } 30 | 31 | // GET: api/Blogs/5 32 | [ResponseType(typeof(Blog))] 33 | public IHttpActionResult GetBlog(int id) 34 | { 35 | Blog blog = _blogService.GetBlog(id); 36 | if (blog == null) 37 | { 38 | return NotFound(); 39 | } 40 | 41 | return Ok(blog); 42 | } 43 | 44 | // PUT: api/Blogs/5 45 | [ResponseType(typeof(void))] 46 | public IHttpActionResult PutBlog(int id, Blog blog) 47 | { 48 | if (!ModelState.IsValid) 49 | { 50 | return BadRequest(ModelState); 51 | } 52 | 53 | if (id != blog.ID) 54 | { 55 | return BadRequest(); 56 | } 57 | 58 | _blogService.UpdateBlog(blog); 59 | 60 | try 61 | { 62 | _blogService.SaveBlog(); 63 | } 64 | catch (DbUpdateConcurrencyException) 65 | { 66 | if (!BlogExists(id)) 67 | { 68 | return NotFound(); 69 | } 70 | else 71 | { 72 | throw; 73 | } 74 | } 75 | 76 | return StatusCode(HttpStatusCode.NoContent); 77 | } 78 | 79 | // POST: api/Blogs 80 | [ResponseType(typeof(Blog))] 81 | public IHttpActionResult PostBlog(Blog blog) 82 | { 83 | if (!ModelState.IsValid) 84 | { 85 | return BadRequest(ModelState); 86 | } 87 | 88 | _blogService.CreateBlog(blog); 89 | 90 | return CreatedAtRoute("DefaultApi", new { id = blog.ID }, blog); 91 | } 92 | 93 | // DELETE: api/Blogs/5 94 | [ResponseType(typeof(Blog))] 95 | public IHttpActionResult DeleteBlog(int id) 96 | { 97 | Blog blog = _blogService.GetBlog(id); 98 | if (blog == null) 99 | { 100 | return NotFound(); 101 | } 102 | 103 | _blogService.DeleteBlog(blog); 104 | 105 | return Ok(blog); 106 | } 107 | 108 | private bool BlogExists(int id) 109 | { 110 | return _blogService.GetBlog(id) != null; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/CustomAssembliesResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Web.Http.Dispatcher; 8 | using UnitTestingWebAPI.API.Core.Controllers; 9 | 10 | namespace UnitTestingWebAPI.API.Core 11 | { 12 | public class CustomAssembliesResolver : DefaultAssembliesResolver 13 | { 14 | public override ICollection GetAssemblies() 15 | { 16 | var baseAssemblies = base.GetAssemblies().ToList(); 17 | var assemblies = new List(baseAssemblies) { typeof(BlogsController).Assembly }; 18 | baseAssemblies.AddRange(assemblies); 19 | 20 | return baseAssemblies.Distinct().ToList(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/Filters/ArticlesReversedFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Web.Http.Filters; 8 | using UnitTestingWebAPI.Domain; 9 | 10 | namespace UnitTestingWebAPI.API.Core.Filters 11 | { 12 | public class ArticlesReversedFilter : ActionFilterAttribute 13 | { 14 | public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 15 | { 16 | var objectContent = actionExecutedContext.Response.Content as ObjectContent; 17 | if (objectContent != null) 18 | { 19 | List
_articles = objectContent.Value as List
; 20 | if (_articles != null && _articles.Count > 0) 21 | { 22 | _articles.Reverse(); 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/MediaTypeFormatters/ArticleFormatter.cs: -------------------------------------------------------------------------------- 1 | #region Using 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Net.Http; 9 | using System.Net.Http.Formatting; 10 | using System.Net.Http.Headers; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | using UnitTestingWebAPI.Domain; 14 | #endregion 15 | 16 | namespace UnitTestingWebAPI.API.Core.MediaTypeFormatters 17 | { 18 | public class ArticleFormatter : BufferedMediaTypeFormatter 19 | { 20 | public ArticleFormatter() 21 | { 22 | SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/article")); 23 | } 24 | 25 | public override bool CanReadType(Type type) 26 | { 27 | return false; 28 | } 29 | 30 | public override bool CanWriteType(Type type) 31 | { 32 | //for single article object 33 | if (type == typeof(Article)) 34 | return true; 35 | else 36 | { 37 | // for multiple article objects 38 | Type _type = typeof(IEnumerable
); 39 | return _type.IsAssignableFrom(type); 40 | } 41 | } 42 | 43 | public override void WriteToStream(Type type, 44 | object value, 45 | Stream writeStream, 46 | HttpContent content) 47 | { 48 | using (StreamWriter writer = new StreamWriter(writeStream)) 49 | { 50 | var articles = value as IEnumerable
; 51 | if (articles != null) 52 | { 53 | foreach (var article in articles) 54 | { 55 | writer.Write(String.Format("[{0},\"{1}\",\"{2}\",\"{3}\",\"{4}\"]", 56 | article.ID, 57 | article.Title, 58 | article.Author, 59 | article.URL, 60 | article.Contents)); 61 | } 62 | } 63 | else 64 | { 65 | var _article = value as Article; 66 | if (_article == null) 67 | { 68 | throw new InvalidOperationException("Cannot serialize type"); 69 | } 70 | writer.Write(String.Format("[{0},\"{1}\",\"{2}\",\"{3}\",\"{4}\"]", 71 | _article.ID, 72 | _article.Title, 73 | _article.Author, 74 | _article.URL, 75 | _article.Contents)); 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/MessageHandlers/EndRequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace UnitTestingWebAPI.API.Core.MessageHandlers 11 | { 12 | public class EndRequestHandler : DelegatingHandler 13 | { 14 | async protected override Task SendAsync( 15 | HttpRequestMessage request, CancellationToken cancellationToken) 16 | { 17 | if (request.RequestUri.AbsoluteUri.Contains("test")) 18 | { 19 | var response = new HttpResponseMessage(HttpStatusCode.OK) 20 | { 21 | Content = new StringContent("Unit testing message handlers!") 22 | }; 23 | 24 | var tsc = new TaskCompletionSource(); 25 | tsc.SetResult(response); 26 | return await tsc.Task; 27 | } 28 | else 29 | { 30 | return await base.SendAsync(request, cancellationToken); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/MessageHandlers/HeaderAppenderHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace UnitTestingWebAPI.API.Core.MessageHandlers 10 | { 11 | public class HeaderAppenderHandler : DelegatingHandler 12 | { 13 | async protected override Task SendAsync( 14 | HttpRequestMessage request, CancellationToken cancellationToken) 15 | { 16 | HttpResponseMessage response = await base.SendAsync(request, cancellationToken); 17 | 18 | response.Headers.Add("X-WebAPI-Header", "Web API Unit testing in chsakell's blog."); 19 | return response; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnitTestingWebAPI.API.Core")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnitTestingWebAPI.API.Core")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c8fd4f89-a6d0-4186-a176-c95923596825")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/UnitTestingWebAPI.API.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {04D7AE21-CABB-44A5-882C-44890AA19092} 8 | Library 9 | Properties 10 | UnitTestingWebAPI.API.Core 11 | UnitTestingWebAPI.API.Core 12 | v4.5.1 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 37 | 38 | 39 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 40 | 41 | 42 | False 43 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 44 | 45 | 46 | 47 | 48 | 49 | 50 | False 51 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll 52 | 53 | 54 | False 55 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {004555f2-5b29-49d0-98fd-60d57e0de8aa} 80 | UnitTestingWebAPI.Domain 81 | 82 | 83 | {ea36fd16-a613-4f31-8bff-94ece2028a63} 84 | UnitTestingWebAPI.Service 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 93 | 94 | 95 | 96 | 103 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API.Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="UnitTestingWebAPI.API.Global" Language="C#" %> 2 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Http; 6 | using System.Web.Security; 7 | using System.Web.SessionState; 8 | using UnitTestingWebAPI.Data; 9 | 10 | namespace UnitTestingWebAPI.API 11 | { 12 | public class Global : System.Web.HttpApplication 13 | { 14 | 15 | protected void Application_Start(object sender, EventArgs e) 16 | { 17 | // Init database 18 | System.Data.Entity.Database.SetInitializer(new BloggerInitializer()); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnitTestingWebAPI.API")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnitTestingWebAPI.API")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a8bc6242-6a19-4605-8b81-94809131d4b0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/Startup.cs: -------------------------------------------------------------------------------- 1 | #region Using 2 | using Autofac; 3 | using Autofac.Integration.WebApi; 4 | using Owin; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Web; 9 | using System.Web.Http; 10 | using System.Web.Http.Dispatcher; 11 | using UnitTestingWebAPI.API.Core; 12 | using UnitTestingWebAPI.API.Core.Controllers; 13 | using UnitTestingWebAPI.API.Core.MediaTypeFormatters; 14 | using UnitTestingWebAPI.Data.Infrastructure; 15 | using UnitTestingWebAPI.Data.Repositories; 16 | using UnitTestingWebAPI.Service; 17 | #endregion 18 | 19 | namespace UnitTestingWebAPI.API 20 | { 21 | public class Startup 22 | { 23 | public void Configuration(IAppBuilder appBuilder) 24 | { 25 | var config = new HttpConfiguration(); 26 | config.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver()); 27 | config.Formatters.Add(new ArticleFormatter()); 28 | 29 | config.Routes.MapHttpRoute( 30 | name: "DefaultApi", 31 | routeTemplate: "api/{controller}/{id}", 32 | defaults: new { id = RouteParameter.Optional } 33 | ); 34 | 35 | 36 | // Autofac configuration 37 | var builder = new ContainerBuilder(); 38 | builder.RegisterApiControllers(typeof(BlogsController).Assembly); 39 | builder.RegisterType().As().InstancePerRequest(); 40 | builder.RegisterType().As().InstancePerRequest(); 41 | 42 | //Repositories 43 | builder.RegisterAssemblyTypes(typeof(BlogRepository).Assembly) 44 | .Where(t => t.Name.EndsWith("Repository")) 45 | .AsImplementedInterfaces().InstancePerRequest(); 46 | // Services 47 | builder.RegisterAssemblyTypes(typeof(ArticleService).Assembly) 48 | .Where(t => t.Name.EndsWith("Service")) 49 | .AsImplementedInterfaces().InstancePerRequest(); 50 | 51 | IContainer container = builder.Build(); 52 | config.DependencyResolver = new AutofacWebApiDependencyResolver(container); 53 | 54 | appBuilder.UseWebApi(config); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/UnitTestingWebAPI.API.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {6D9E0639-885F-4B25-A5C4-1BEA8CF2F8C4} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | UnitTestingWebAPI.API 15 | UnitTestingWebAPI.API 16 | v4.5.1 17 | true 18 | 19 | 20 | 21 | 22 | ..\ 23 | true 24 | 25 | 26 | true 27 | full 28 | false 29 | bin\ 30 | DEBUG;TRACE 31 | prompt 32 | 4 33 | 34 | 35 | pdbonly 36 | true 37 | bin\ 38 | TRACE 39 | prompt 40 | 4 41 | 42 | 43 | 44 | ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll 45 | 46 | 47 | ..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll 48 | 49 | 50 | ..\packages\Autofac.WebApi2.3.4.0\lib\net45\Autofac.Integration.WebApi.dll 51 | 52 | 53 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 54 | 55 | 56 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 57 | 58 | 59 | 60 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll 61 | 62 | 63 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll 64 | 65 | 66 | True 67 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 68 | 69 | 70 | False 71 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 72 | 73 | 74 | ..\packages\Owin.1.0\lib\net40\Owin.dll 75 | 76 | 77 | 78 | False 79 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | False 92 | ..\packages\Microsoft.AspNet.WebPages.3.1.0\lib\net45\System.Web.Helpers.dll 93 | 94 | 95 | False 96 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll 97 | 98 | 99 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll 100 | 101 | 102 | False 103 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll 104 | 105 | 106 | True 107 | ..\packages\Microsoft.AspNet.Mvc.5.1.0\lib\net45\System.Web.Mvc.dll 108 | 109 | 110 | False 111 | ..\packages\Microsoft.AspNet.Razor.3.1.0\lib\net45\System.Web.Razor.dll 112 | 113 | 114 | False 115 | ..\packages\Microsoft.AspNet.WebPages.3.1.0\lib\net45\System.Web.WebPages.dll 116 | 117 | 118 | False 119 | ..\packages\Microsoft.AspNet.WebPages.3.1.0\lib\net45\System.Web.WebPages.Deployment.dll 120 | 121 | 122 | False 123 | ..\packages\Microsoft.AspNet.WebPages.3.1.0\lib\net45\System.Web.WebPages.Razor.dll 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | Web.config 137 | 138 | 139 | Web.config 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | Global.asax 149 | 150 | 151 | 152 | 153 | 154 | 155 | {04d7ae21-cabb-44a5-882c-44890aa19092} 156 | UnitTestingWebAPI.API.Core 157 | 158 | 159 | {d9166d82-be4e-4664-bbcc-7d31c274cb92} 160 | UnitTestingWebAPI.Data 161 | 162 | 163 | {ea36fd16-a613-4f31-8bff-94ece2028a63} 164 | UnitTestingWebAPI.Service 165 | 166 | 167 | 168 | 10.0 169 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | True 179 | True 180 | 56032 181 | / 182 | http://localhost:56032/ 183 | False 184 | False 185 | 186 | 187 | False 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 196 | 197 | 198 | 199 | 206 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.API/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/BloggerEntities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnitTestingWebAPI.Data.Configurations; 8 | using UnitTestingWebAPI.Domain; 9 | 10 | namespace UnitTestingWebAPI.Data 11 | { 12 | public class BloggerEntities : DbContext 13 | { 14 | public BloggerEntities() 15 | : base("BloggerEntities") 16 | { 17 | Configuration.ProxyCreationEnabled = false; 18 | } 19 | 20 | public DbSet Blogs { get; set; } 21 | public DbSet
Articles { get; set; } 22 | 23 | public virtual void Commit() 24 | { 25 | base.SaveChanges(); 26 | } 27 | 28 | protected override void OnModelCreating(DbModelBuilder modelBuilder) 29 | { 30 | modelBuilder.Configurations.Add(new ArticleConfiguration()); 31 | modelBuilder.Configurations.Add(new BlogConfiguration()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/BloggerInitializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnitTestingWebAPI.Domain; 8 | 9 | namespace UnitTestingWebAPI.Data 10 | { 11 | public class BloggerInitializer : DropCreateDatabaseIfModelChanges 12 | { 13 | protected override void Seed(BloggerEntities context) 14 | { 15 | GetBlogs().ForEach(b => context.Blogs.Add(b)); 16 | 17 | context.Commit(); 18 | } 19 | 20 | public static List GetBlogs() 21 | { 22 | List _blogs = new List(); 23 | 24 | // Add two Blogs 25 | Blog _chsakellsBlog = new Blog() 26 | { 27 | Name = "chsakell's Blog", 28 | URL = "http://chsakell.com/", 29 | Owner = "Chris Sakellarios", 30 | Articles = GetChsakellsArticles() 31 | }; 32 | 33 | Blog _dotNetCodeGeeks = new Blog() 34 | { 35 | Name = "DotNETCodeGeeks", 36 | URL = "dotnetcodegeeks", 37 | Owner = ".NET Code Geeks", 38 | Articles = GetDotNETGeeksArticles() 39 | }; 40 | 41 | _blogs.Add(_chsakellsBlog); 42 | _blogs.Add(_dotNetCodeGeeks); 43 | 44 | return _blogs; 45 | } 46 | 47 | public static List
GetChsakellsArticles() 48 | { 49 | List
_articles = new List
(); 50 | 51 | Article _oData = new Article() 52 | { 53 | Author = "Chris S.", 54 | Title = "ASP.NET Web API feat. OData", 55 | URL = "http://chsakell.com/2015/04/04/asp-net-web-api-feat-odata/", 56 | Contents = @"OData is an open standard protocol allowing the creation and consumption of queryable 57 | and interoperable RESTful APIs. It was initiated by Microsoft and it’s mostly known to 58 | .NET Developers from WCF Data Services. There are many other server platforms supporting 59 | OData services such as Node.js, PHP, Java and SQL Server Reporting Services. More over, 60 | Web API also supports OData and this post will show you how to integrate those two.." 61 | }; 62 | 63 | Article _wcfCustomSecurity= new Article() 64 | { 65 | Author = "Chris S.", 66 | Title = "Secure WCF Services with custom encrypted tokens", 67 | URL = "http://chsakell.com/2014/12/13/secure-wcf-services-with-custom-encrypted-tokens/", 68 | Contents = @"Windows Communication Foundation framework comes with a lot of options out of the box, 69 | concerning the security logic you will apply to your services. Different bindings can be 70 | used for certain kind and levels of security. Even the BasicHttpBinding binding supports 71 | some types of security. There are some times though where you cannot or don’t want to use 72 | WCF security available options and hence, you need to develop your own authentication logic 73 | accoarding to your business needs." 74 | }; 75 | 76 | _articles.Add(_oData); 77 | _articles.Add(_wcfCustomSecurity); 78 | 79 | return _articles; 80 | } 81 | 82 | public static List
GetDotNETGeeksArticles() 83 | { 84 | List
_articles = new List
(); 85 | 86 | Article _angularFeatWebAPI = new Article() 87 | { 88 | Author = "Gordon Beeming", 89 | Title = "AngularJS feat. Web API", 90 | URL = "http://www.dotnetcodegeeks.com/2015/05/angularjs-feat-web-api.html", 91 | Contents = @"Developing Web applications using AngularJS and Web API can be quite amuzing. You can pick 92 | this architecture in case you have in mind a web application with limitted page refreshes or 93 | post backs to the server while each application’s View is based on partial data retrieved from it." 94 | }; 95 | 96 | _articles.Add(_angularFeatWebAPI); 97 | 98 | return _articles; 99 | } 100 | 101 | public static List
GetAllArticles() 102 | { 103 | List
_articles = new List
(); 104 | _articles.AddRange(GetChsakellsArticles()); 105 | _articles.AddRange(GetDotNETGeeksArticles()); 106 | 107 | return _articles; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Configurations/ArticleConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity.ModelConfiguration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnitTestingWebAPI.Domain; 8 | 9 | namespace UnitTestingWebAPI.Data.Configurations 10 | { 11 | public class ArticleConfiguration : EntityTypeConfiguration
12 | { 13 | public ArticleConfiguration() 14 | { 15 | ToTable("Article"); 16 | Property(a => a.Title).IsRequired().HasMaxLength(100); 17 | Property(a => a.Contents).IsRequired(); 18 | Property(a => a.Author).IsRequired().HasMaxLength(50); 19 | Property(a => a.URL).IsRequired().HasMaxLength(200); 20 | Property(a => a.DateCreated).HasColumnType("datetime2"); 21 | Property(a => a.DateEdited).HasColumnType("datetime2"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Configurations/BlogConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity.ModelConfiguration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnitTestingWebAPI.Domain; 8 | 9 | namespace UnitTestingWebAPI.Data.Configurations 10 | { 11 | public class BlogConfiguration : EntityTypeConfiguration 12 | { 13 | public BlogConfiguration() 14 | { 15 | ToTable("Blog"); 16 | Property(b => b.Name).IsRequired().HasMaxLength(100); 17 | Property(b => b.URL).IsRequired().HasMaxLength(200); 18 | Property(b => b.Owner).IsRequired().HasMaxLength(50); 19 | Property(b => b.DateCreated).HasColumnType("datetime2"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Infrastructure/DbFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnitTestingWebAPI.Data.Infrastructure 8 | { 9 | public class DbFactory : Disposable, IDbFactory 10 | { 11 | BloggerEntities dbContext; 12 | 13 | public BloggerEntities Init() 14 | { 15 | return dbContext ?? (dbContext = new BloggerEntities()); 16 | } 17 | 18 | protected override void DisposeCore() 19 | { 20 | if (dbContext != null) 21 | dbContext.Dispose(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Infrastructure/Disposable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnitTestingWebAPI.Data.Infrastructure 8 | { 9 | public class Disposable : IDisposable 10 | { 11 | private bool isDisposed; 12 | 13 | ~Disposable() 14 | { 15 | Dispose(false); 16 | } 17 | 18 | public void Dispose() 19 | { 20 | Dispose(true); 21 | GC.SuppressFinalize(this); 22 | } 23 | private void Dispose(bool disposing) 24 | { 25 | if (!isDisposed && disposing) 26 | { 27 | DisposeCore(); 28 | } 29 | 30 | isDisposed = true; 31 | } 32 | 33 | // Ovveride this to dispose custom objects 34 | protected virtual void DisposeCore() 35 | { 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Infrastructure/IDbFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnitTestingWebAPI.Data.Infrastructure 8 | { 9 | public interface IDbFactory : IDisposable 10 | { 11 | BloggerEntities Init(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Infrastructure/IRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UnitTestingWebAPI.Data.Infrastructure 9 | { 10 | public interface IRepository where T : class 11 | { 12 | // Marks an entity as new 13 | void Add(T entity); 14 | // Marks an entity as modified 15 | void Update(T entity); 16 | // Marks an entity to be removed 17 | void Delete(T entity); 18 | void Delete(Expression> where); 19 | // Get an entity by int id 20 | T GetById(int id); 21 | // Get an entity using delegate 22 | T Get(Expression> where); 23 | // Gets all entities of type T 24 | IEnumerable GetAll(); 25 | // Gets entities using delegate 26 | IEnumerable GetMany(Expression> where); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Infrastructure/IUnitOfWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnitTestingWebAPI.Data.Infrastructure 8 | { 9 | public interface IUnitOfWork 10 | { 11 | void Commit(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Infrastructure/RepositoryBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace UnitTestingWebAPI.Data.Infrastructure 10 | { 11 | public abstract class RepositoryBase where T : class 12 | { 13 | #region Properties 14 | private BloggerEntities dataContext; 15 | private readonly IDbSet dbSet; 16 | 17 | protected IDbFactory DbFactory 18 | { 19 | get; 20 | private set; 21 | } 22 | 23 | protected BloggerEntities DbContext 24 | { 25 | get { return dataContext ?? (dataContext = DbFactory.Init()); } 26 | } 27 | #endregion 28 | 29 | protected RepositoryBase(IDbFactory dbFactory) 30 | { 31 | DbFactory = dbFactory; 32 | dbSet = DbContext.Set(); 33 | } 34 | 35 | #region Implementation 36 | public virtual void Add(T entity) 37 | { 38 | dbSet.Add(entity); 39 | } 40 | 41 | public virtual void Update(T entity) 42 | { 43 | dbSet.Attach(entity); 44 | dataContext.Entry(entity).State = EntityState.Modified; 45 | } 46 | 47 | public virtual void Delete(T entity) 48 | { 49 | dbSet.Remove(entity); 50 | } 51 | 52 | public virtual void Delete(Expression> where) 53 | { 54 | IEnumerable objects = dbSet.Where(where).AsEnumerable(); 55 | foreach (T obj in objects) 56 | dbSet.Remove(obj); 57 | } 58 | 59 | public virtual T GetById(int id) 60 | { 61 | return dbSet.Find(id); 62 | } 63 | 64 | public virtual IEnumerable GetAll() 65 | { 66 | return dbSet.ToList(); 67 | } 68 | 69 | public virtual IEnumerable GetMany(Expression> where) 70 | { 71 | return dbSet.Where(where).ToList(); 72 | } 73 | 74 | public T Get(Expression> where) 75 | { 76 | return dbSet.Where(where).FirstOrDefault(); 77 | } 78 | 79 | #endregion 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Infrastructure/UnitOfWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnitTestingWebAPI.Data.Infrastructure 8 | { 9 | public class UnitOfWork : IUnitOfWork 10 | { 11 | private readonly IDbFactory dbFactory; 12 | private BloggerEntities dbContext; 13 | 14 | public UnitOfWork(IDbFactory dbFactory) 15 | { 16 | this.dbFactory = dbFactory; 17 | } 18 | 19 | public BloggerEntities DbContext 20 | { 21 | get { return dbContext ?? (dbContext = dbFactory.Init()); } 22 | } 23 | 24 | public void Commit() 25 | { 26 | DbContext.Commit(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnitTestingWebAPI.Data")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnitTestingWebAPI.Data")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a24500b5-c90e-4c6e-a7fb-1af1b513b1d3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Repositories/ArticleRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnitTestingWebAPI.Data.Infrastructure; 7 | using UnitTestingWebAPI.Domain; 8 | 9 | namespace UnitTestingWebAPI.Data.Repositories 10 | { 11 | public class ArticleRepository : RepositoryBase
, IArticleRepository 12 | { 13 | public ArticleRepository(IDbFactory dbFactory) 14 | : base(dbFactory) { } 15 | 16 | public Article GetArticleByTitle(string articleTitle) 17 | { 18 | var _article = this.DbContext.Articles.Where(b => b.Title == articleTitle).FirstOrDefault(); 19 | 20 | return _article; 21 | } 22 | } 23 | 24 | public interface IArticleRepository : IRepository
25 | { 26 | Article GetArticleByTitle(string articleTitle); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/Repositories/BlogRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnitTestingWebAPI.Data.Infrastructure; 7 | using UnitTestingWebAPI.Domain; 8 | 9 | namespace UnitTestingWebAPI.Data.Repositories 10 | { 11 | public class BlogRepository : RepositoryBase, IBlogRepository 12 | { 13 | public BlogRepository(IDbFactory dbFactory) 14 | : base(dbFactory) { } 15 | 16 | public Blog GetBlogByName(string blogName) 17 | { 18 | var _blog = this.DbContext.Blogs.Where(b => b.Name == blogName).FirstOrDefault(); 19 | 20 | return _blog; 21 | } 22 | } 23 | 24 | public interface IBlogRepository : IRepository 25 | { 26 | Blog GetBlogByName(string blogName); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/UnitTestingWebAPI.Data.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D9166D82-BE4E-4664-BBCC-7D31C274CB92} 8 | Library 9 | Properties 10 | UnitTestingWebAPI.Data 11 | UnitTestingWebAPI.Data 12 | v4.5.1 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 37 | 38 | 39 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {004555f2-5b29-49d0-98fd-60d57e0de8aa} 69 | UnitTestingWebAPI.Domain 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 82 | 83 | 84 | 85 | 92 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Data/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Domain/Article.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnitTestingWebAPI.Domain 8 | { 9 | public class Article 10 | { 11 | public int ID { get; set; } 12 | public string Title { get; set; } 13 | public string Contents { get; set; } 14 | public string Author { get; set; } 15 | public string URL { get; set; } 16 | public DateTime DateCreated { get; set; } 17 | public DateTime DateEdited { get; set; } 18 | 19 | public int BlogID { get; set; } 20 | public virtual Blog Blog { get; set; } 21 | 22 | public Article() 23 | { 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Domain/Blog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnitTestingWebAPI.Domain 8 | { 9 | public class Blog 10 | { 11 | public int ID { get; set; } 12 | public string Name { get; set; } 13 | public string URL { get; set; } 14 | public string Owner { get; set; } 15 | public DateTime DateCreated { get; set; } 16 | public virtual ICollection
Articles { get; set; } 17 | 18 | public Blog() 19 | { 20 | Articles = new HashSet
(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Domain/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnitTestingWebAPI.Domain")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnitTestingWebAPI.Domain")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("68b444bc-9010-46a4-bb5f-5b1d86df42fc")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Domain/UnitTestingWebAPI.Domain.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {004555F2-5B29-49D0-98FD-60D57E0DE8AA} 8 | Library 9 | Properties 10 | UnitTestingWebAPI.Domain 11 | UnitTestingWebAPI.Domain 12 | v4.5.1 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 54 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Service/ArticleService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnitTestingWebAPI.Data.Infrastructure; 7 | using UnitTestingWebAPI.Data.Repositories; 8 | using UnitTestingWebAPI.Domain; 9 | 10 | namespace UnitTestingWebAPI.Service 11 | { 12 | // operations you want to expose 13 | public interface IArticleService 14 | { 15 | IEnumerable
GetArticles(string name = null); 16 | Article GetArticle(int id); 17 | Article GetArticle(string name); 18 | void CreateArticle(Article article); 19 | void UpdateArticle(Article article); 20 | void DeleteArticle(Article article); 21 | void SaveArticle(); 22 | } 23 | 24 | public class ArticleService : IArticleService 25 | { 26 | private readonly IArticleRepository articlesRepository; 27 | private readonly IUnitOfWork unitOfWork; 28 | 29 | public ArticleService(IArticleRepository articlesRepository, IUnitOfWork unitOfWork) 30 | { 31 | this.articlesRepository = articlesRepository; 32 | this.unitOfWork = unitOfWork; 33 | } 34 | 35 | #region IArticleService Members 36 | 37 | public IEnumerable
GetArticles(string title = null) 38 | { 39 | if (string.IsNullOrEmpty(title)) 40 | return articlesRepository.GetAll(); 41 | else 42 | return articlesRepository.GetAll().Where(c => c.Title.ToLower().Contains(title.ToLower())); 43 | } 44 | 45 | public Article GetArticle(int id) 46 | { 47 | var article = articlesRepository.GetById(id); 48 | return article; 49 | } 50 | 51 | public Article GetArticle(string title) 52 | { 53 | var article = articlesRepository.GetArticleByTitle(title); 54 | return article; 55 | } 56 | 57 | public void CreateArticle(Article article) 58 | { 59 | articlesRepository.Add(article); 60 | } 61 | 62 | public void UpdateArticle(Article article) 63 | { 64 | articlesRepository.Update(article); 65 | } 66 | 67 | public void DeleteArticle(Article article) 68 | { 69 | articlesRepository.Delete(article); 70 | } 71 | 72 | public void SaveArticle() 73 | { 74 | unitOfWork.Commit(); 75 | } 76 | 77 | #endregion 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Service/BlogService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnitTestingWebAPI.Data.Infrastructure; 7 | using UnitTestingWebAPI.Data.Repositories; 8 | using UnitTestingWebAPI.Domain; 9 | 10 | namespace UnitTestingWebAPI.Service 11 | { 12 | // operations you want to expose 13 | public interface IBlogService 14 | { 15 | IEnumerable GetBlogs(string name = null); 16 | Blog GetBlog(int id); 17 | Blog GetBlog(string name); 18 | void CreateBlog(Blog blog); 19 | void UpdateBlog(Blog blog); 20 | void SaveBlog(); 21 | void DeleteBlog(Blog blog); 22 | } 23 | 24 | public class BlogService : IBlogService 25 | { 26 | private readonly IBlogRepository blogsRepository; 27 | private readonly IUnitOfWork unitOfWork; 28 | 29 | public BlogService(IBlogRepository blogsRepository, IUnitOfWork unitOfWork) 30 | { 31 | this.blogsRepository = blogsRepository; 32 | this.unitOfWork = unitOfWork; 33 | } 34 | 35 | #region IBlogService Members 36 | 37 | public IEnumerable GetBlogs(string name = null) 38 | { 39 | if (string.IsNullOrEmpty(name)) 40 | return blogsRepository.GetAll(); 41 | else 42 | return blogsRepository.GetAll().Where(c => c.Name == name); 43 | } 44 | 45 | public Blog GetBlog(int id) 46 | { 47 | var blog = blogsRepository.GetById(id); 48 | return blog; 49 | } 50 | 51 | public Blog GetBlog(string name) 52 | { 53 | var blog = blogsRepository.GetBlogByName(name); 54 | return blog; 55 | } 56 | 57 | public void CreateBlog(Blog blog) 58 | { 59 | blogsRepository.Add(blog); 60 | } 61 | 62 | public void UpdateBlog(Blog blog) 63 | { 64 | blogsRepository.Update(blog); 65 | } 66 | 67 | public void DeleteBlog(Blog blog) 68 | { 69 | blogsRepository.Delete(blog); 70 | } 71 | 72 | public void SaveBlog() 73 | { 74 | unitOfWork.Commit(); 75 | } 76 | 77 | #endregion 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Service/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnitTestingWebAPI.Service")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnitTestingWebAPI.Service")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7f3be8c4-b828-45dc-8386-57505b87e056")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Service/UnitTestingWebAPI.Service.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EA36FD16-A613-4F31-8BFF-94ECE2028A63} 8 | Library 9 | Properties 10 | UnitTestingWebAPI.Service 11 | UnitTestingWebAPI.Service 12 | v4.5.1 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {d9166d82-be4e-4664-bbcc-7d31c274cb92} 49 | UnitTestingWebAPI.Data 50 | 51 | 52 | {004555f2-5b29-49d0-98fd-60d57e0de8aa} 53 | UnitTestingWebAPI.Domain 54 | 55 | 56 | 57 | 64 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/ActionFilterTests.cs: -------------------------------------------------------------------------------- 1 | #region Using 2 | using Microsoft.Owin.Hosting; 3 | using NUnit.Framework; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Net.Http; 8 | using System.Net.Http.Formatting; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Web.Http.Controllers; 12 | using System.Web.Http.Filters; 13 | using UnitTestingWebAPI.API.Core.Filters; 14 | using UnitTestingWebAPI.Data; 15 | using UnitTestingWebAPI.Domain; 16 | using UnitTestingWebAPI.Tests.Hosting; 17 | #endregion 18 | 19 | namespace UnitTestingWebAPI.Tests 20 | { 21 | [TestFixture] 22 | public class ActionFilterTests 23 | { 24 | #region Variables 25 | private List
_articles; 26 | #endregion 27 | 28 | #region Setup 29 | [SetUp] 30 | public void Setup() 31 | { 32 | _articles = BloggerInitializer.GetAllArticles(); 33 | } 34 | #endregion 35 | 36 | #region Tests 37 | [Test] 38 | public void ShouldSortArticlesByTitle() 39 | { 40 | var filter = new ArticlesReversedFilter(); 41 | var executedContext = new HttpActionExecutedContext(new HttpActionContext 42 | { 43 | Response = new HttpResponseMessage(), 44 | }, null); 45 | 46 | executedContext.Response.Content = new ObjectContent>(new List
(_articles), new JsonMediaTypeFormatter()); 47 | 48 | filter.OnActionExecuted(executedContext); 49 | 50 | var _returnedArticles = executedContext.Response.Content.ReadAsAsync>().Result; 51 | 52 | Assert.That(_returnedArticles.First(), Is.EqualTo(_articles.Last())); 53 | } 54 | 55 | [Test] 56 | public void ShouldCallToControllerActionReverseArticles() 57 | { 58 | //Arrange 59 | var address = "http://localhost:9000/"; 60 | 61 | using (WebApp.Start(address)) 62 | { 63 | HttpClient _client = new HttpClient(); 64 | var response = _client.GetAsync(address + "api/articles").Result; 65 | 66 | var _returnedArticles = response.Content.ReadAsAsync>().Result; 67 | 68 | Assert.That(_returnedArticles.First().Title, Is.EqualTo(BloggerInitializer.GetAllArticles().Last().Title)); 69 | } 70 | } 71 | #endregion 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/ControllerTests.cs: -------------------------------------------------------------------------------- 1 | #region Usings 2 | using Moq; 3 | using NUnit.Framework; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Net.Http; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Web.Http; 12 | using System.Web.Http.Results; 13 | using System.Web.Http.Routing; 14 | using UnitTestingWebAPI.API.Core.Controllers; 15 | using UnitTestingWebAPI.Data; 16 | using UnitTestingWebAPI.Data.Infrastructure; 17 | using UnitTestingWebAPI.Data.Repositories; 18 | using UnitTestingWebAPI.Domain; 19 | using UnitTestingWebAPI.Service; 20 | #endregion 21 | 22 | namespace UnitTestingWebAPI.Tests 23 | { 24 | [TestFixture] 25 | public class ControllerTests 26 | { 27 | #region Variables 28 | IArticleService _articleService; 29 | IArticleRepository _articleRepository; 30 | IUnitOfWork _unitOfWork; 31 | List
_randomArticles; 32 | #endregion 33 | 34 | #region Setup 35 | [SetUp] 36 | public void Setup() 37 | { 38 | _randomArticles = SetupArticles(); 39 | 40 | _articleRepository = SetupArticleRepository(); 41 | _unitOfWork = new Mock().Object; 42 | _articleService = new ArticleService(_articleRepository, _unitOfWork); 43 | } 44 | 45 | public List
SetupArticles() 46 | { 47 | int _counter = new int(); 48 | List
_articles = BloggerInitializer.GetAllArticles(); 49 | 50 | foreach (Article _article in _articles) 51 | _article.ID = ++_counter; 52 | 53 | return _articles; 54 | } 55 | 56 | public IArticleRepository SetupArticleRepository() 57 | { 58 | // Init repository 59 | var repo = new Mock(); 60 | 61 | // Setup mocking behavior 62 | repo.Setup(r => r.GetAll()).Returns(_randomArticles); 63 | 64 | repo.Setup(r => r.GetById(It.IsAny())) 65 | .Returns(new Func( 66 | id => _randomArticles.Find(a => a.ID.Equals(id)))); 67 | 68 | repo.Setup(r => r.Add(It.IsAny
())) 69 | .Callback(new Action
(newArticle => 70 | { 71 | dynamic maxArticleID = _randomArticles.Last().ID; 72 | dynamic nextArticleID = maxArticleID + 1; 73 | newArticle.ID = nextArticleID; 74 | newArticle.DateCreated = DateTime.Now; 75 | _randomArticles.Add(newArticle); 76 | })); 77 | 78 | repo.Setup(r => r.Update(It.IsAny
())) 79 | .Callback(new Action
(x => 80 | { 81 | var oldArticle = _randomArticles.Find(a => a.ID == x.ID); 82 | oldArticle.DateEdited = DateTime.Now; 83 | oldArticle.URL = x.URL; 84 | oldArticle.Title = x.Title; 85 | oldArticle.Contents = x.Contents; 86 | oldArticle.BlogID = x.BlogID; 87 | })); 88 | 89 | repo.Setup(r => r.Delete(It.IsAny
())) 90 | .Callback(new Action
(x => 91 | { 92 | var _articleToRemove = _randomArticles.Find(a => a.ID == x.ID); 93 | 94 | if (_articleToRemove != null) 95 | _randomArticles.Remove(_articleToRemove); 96 | })); 97 | 98 | // Return mock implementation 99 | return repo.Object; 100 | } 101 | 102 | #endregion 103 | 104 | #region Tests 105 | 106 | [Test] 107 | public void ControlerShouldReturnAllArticles() 108 | { 109 | var _articlesController = new ArticlesController(_articleService); 110 | 111 | var result = _articlesController.GetArticles(); 112 | 113 | CollectionAssert.AreEqual(result, _randomArticles); 114 | } 115 | 116 | [Test] 117 | public void ControlerShouldReturnLastArticle() 118 | { 119 | var _articlesController = new ArticlesController(_articleService); 120 | 121 | var result = _articlesController.GetArticle(3) as OkNegotiatedContentResult
; 122 | 123 | Assert.IsNotNull(result); 124 | Assert.AreEqual(result.Content.Title, _randomArticles.Last().Title); 125 | } 126 | 127 | [Test] 128 | public void ControlerShouldPutReturnBadRequestResult() 129 | { 130 | var _articlesController = new ArticlesController(_articleService) 131 | { 132 | Configuration = new HttpConfiguration(), 133 | Request = new HttpRequestMessage 134 | { 135 | Method = HttpMethod.Put, 136 | RequestUri = new Uri("http://localhost/api/articles/-1") 137 | } 138 | }; 139 | 140 | var badresult = _articlesController.PutArticle(-1, new Article() { Title = "Unknown Article" }); 141 | Assert.That(badresult, Is.TypeOf()); 142 | } 143 | 144 | [Test] 145 | public void ControlerShouldPutUpdateFirstArticle() 146 | { 147 | var _articlesController = new ArticlesController(_articleService) 148 | { 149 | Configuration = new HttpConfiguration(), 150 | Request = new HttpRequestMessage 151 | { 152 | Method = HttpMethod.Put, 153 | RequestUri = new Uri("http://localhost/api/articles/1") 154 | } 155 | }; 156 | 157 | IHttpActionResult updateResult = _articlesController.PutArticle(1, new Article() 158 | { 159 | ID = 1, 160 | Title = "ASP.NET Web API feat. OData", 161 | URL = "http://t.co/fuIbNoc7Zh", 162 | Contents = @"OData is an open standard protocol.." 163 | }) as IHttpActionResult; 164 | 165 | Assert.That(updateResult, Is.TypeOf()); 166 | 167 | StatusCodeResult statusCodeResult = updateResult as StatusCodeResult; 168 | 169 | Assert.That(statusCodeResult.StatusCode, Is.EqualTo(HttpStatusCode.NoContent)); 170 | 171 | Assert.That(_randomArticles.First().URL, Is.EqualTo("http://t.co/fuIbNoc7Zh")); 172 | } 173 | 174 | [Test] 175 | public void ControlerShouldPostNewArticle() 176 | { 177 | var article = new Article 178 | { 179 | Title = "Web API Unit Testing", 180 | URL = "http://chsakell.com/web-api-unit-testing", 181 | Author = "Chris Sakellarios", 182 | DateCreated = DateTime.Now, 183 | Contents = "Unit testing Web API.." 184 | }; 185 | 186 | var _articlesController = new ArticlesController(_articleService) 187 | { 188 | Configuration = new HttpConfiguration(), 189 | Request = new HttpRequestMessage 190 | { 191 | Method = HttpMethod.Post, 192 | RequestUri = new Uri("http://localhost/api/articles") 193 | } 194 | }; 195 | 196 | _articlesController.Configuration.MapHttpAttributeRoutes(); 197 | _articlesController.Configuration.EnsureInitialized(); 198 | _articlesController.RequestContext.RouteData = new HttpRouteData( 199 | new HttpRoute(), new HttpRouteValueDictionary { { "_articlesController", "Articles" } }); 200 | var result = _articlesController.PostArticle(article) as CreatedAtRouteNegotiatedContentResult
; 201 | 202 | Assert.That(result.RouteName, Is.EqualTo("DefaultApi")); 203 | Assert.That(result.Content.ID, Is.EqualTo(result.RouteValues["id"])); 204 | Assert.That(result.Content.ID, Is.EqualTo(_randomArticles.Max(a => a.ID))); 205 | } 206 | 207 | [Test] 208 | public void ControlerShouldNotPostNewArticle() 209 | { 210 | var article = new Article 211 | { 212 | Title = "Web API Unit Testing", 213 | URL = "http://chsakell.com/web-api-unit-testing", 214 | Author = "Chris Sakellarios", 215 | DateCreated = DateTime.Now, 216 | Contents = null 217 | }; 218 | 219 | var _articlesController = new ArticlesController(_articleService) 220 | { 221 | Configuration = new HttpConfiguration(), 222 | Request = new HttpRequestMessage 223 | { 224 | Method = HttpMethod.Post, 225 | RequestUri = new Uri("http://localhost/api/articles") 226 | } 227 | }; 228 | 229 | _articlesController.Configuration.MapHttpAttributeRoutes(); 230 | _articlesController.Configuration.EnsureInitialized(); 231 | _articlesController.RequestContext.RouteData = new HttpRouteData( 232 | new HttpRoute(), new HttpRouteValueDictionary { { "Controller", "Articles" } }); 233 | _articlesController.ModelState.AddModelError("Contents", "Contents is required field"); 234 | 235 | var result = _articlesController.PostArticle(article) as InvalidModelStateResult; 236 | 237 | Assert.That(result.ModelState.Count, Is.EqualTo(1)); 238 | Assert.That(result.ModelState.IsValid, Is.EqualTo(false)); 239 | } 240 | 241 | #endregion 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/Helpers/ControllerActionSelector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Web.Http; 9 | using System.Web.Http.Controllers; 10 | using System.Web.Http.Dispatcher; 11 | using System.Web.Http.Hosting; 12 | using System.Web.Http.Routing; 13 | 14 | namespace UnitTestingWebAPI.Tests.Helpers 15 | { 16 | public class ControllerActionSelector 17 | { 18 | #region Variables 19 | HttpConfiguration config; 20 | HttpRequestMessage request; 21 | IHttpRouteData routeData; 22 | IHttpControllerSelector controllerSelector; 23 | HttpControllerContext controllerContext; 24 | #endregion 25 | 26 | #region Constructor 27 | public ControllerActionSelector(HttpConfiguration conf, HttpRequestMessage req) 28 | { 29 | config = conf; 30 | request = req; 31 | routeData = config.Routes.GetRouteData(request); 32 | request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData; 33 | controllerSelector = new DefaultHttpControllerSelector(config); 34 | controllerContext = new HttpControllerContext(config, routeData, request); 35 | } 36 | #endregion 37 | 38 | #region Methods 39 | public string GetActionName() 40 | { 41 | if (controllerContext.ControllerDescriptor == null) 42 | GetControllerType(); 43 | 44 | var actionSelector = new ApiControllerActionSelector(); 45 | var descriptor = actionSelector.SelectAction(controllerContext); 46 | 47 | return descriptor.ActionName; 48 | } 49 | 50 | public Type GetControllerType() 51 | { 52 | var descriptor = controllerSelector.SelectController(request); 53 | controllerContext.ControllerDescriptor = descriptor; 54 | return descriptor.ControllerType; 55 | } 56 | #endregion 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/Hosting/Startup.cs: -------------------------------------------------------------------------------- 1 | #region Using 2 | using Autofac; 3 | using Autofac.Integration.WebApi; 4 | using Moq; 5 | using Owin; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Web.Http; 12 | using System.Web.Http.Dispatcher; 13 | using System.Web.Http.SelfHost; 14 | using UnitTestingWebAPI.API.Core; 15 | using UnitTestingWebAPI.API.Core.Controllers; 16 | using UnitTestingWebAPI.API.Core.Filters; 17 | using UnitTestingWebAPI.API.Core.MessageHandlers; 18 | using UnitTestingWebAPI.Data; 19 | using UnitTestingWebAPI.Data.Infrastructure; 20 | using UnitTestingWebAPI.Data.Repositories; 21 | using UnitTestingWebAPI.Domain; 22 | using UnitTestingWebAPI.Service; 23 | #endregion 24 | 25 | namespace UnitTestingWebAPI.Tests.Hosting 26 | { 27 | public class Startup 28 | { 29 | public void Configuration(IAppBuilder appBuilder) 30 | { 31 | var config = new HttpConfiguration(); 32 | config.MessageHandlers.Add(new HeaderAppenderHandler()); 33 | config.MessageHandlers.Add(new EndRequestHandler()); 34 | config.Filters.Add(new ArticlesReversedFilter()); 35 | config.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver()); 36 | 37 | config.Routes.MapHttpRoute( 38 | name: "DefaultApi", 39 | routeTemplate: "api/{controller}/{id}", 40 | defaults: new { id = RouteParameter.Optional } 41 | ); 42 | config.MapHttpAttributeRoutes(); 43 | 44 | // Autofac configuration 45 | var builder = new ContainerBuilder(); 46 | builder.RegisterApiControllers(typeof(ArticlesController).Assembly); 47 | 48 | // Unit of Work 49 | var _unitOfWork = new Mock(); 50 | builder.RegisterInstance(_unitOfWork.Object).As(); 51 | 52 | //Repositories 53 | var _articlesRepository = new Mock(); 54 | _articlesRepository.Setup(x => x.GetAll()).Returns( 55 | BloggerInitializer.GetAllArticles() 56 | ); 57 | builder.RegisterInstance(_articlesRepository.Object).As(); 58 | 59 | var _blogsRepository = new Mock(); 60 | _blogsRepository.Setup(x => x.GetAll()).Returns( 61 | BloggerInitializer.GetBlogs 62 | ); 63 | builder.RegisterInstance(_blogsRepository.Object).As(); 64 | 65 | // Services 66 | builder.RegisterAssemblyTypes(typeof(ArticleService).Assembly) 67 | .Where(t => t.Name.EndsWith("Service")) 68 | .AsImplementedInterfaces().InstancePerRequest(); 69 | 70 | builder.RegisterInstance(new ArticleService(_articlesRepository.Object, _unitOfWork.Object)); 71 | builder.RegisterInstance(new BlogService(_blogsRepository.Object, _unitOfWork.Object)); 72 | 73 | IContainer container = builder.Build(); 74 | config.DependencyResolver = new AutofacWebApiDependencyResolver(container); 75 | 76 | appBuilder.UseWebApi(config); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/MediaTypeFormatterTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using UnitTestingWebAPI.API.Core.MediaTypeFormatters; 9 | using UnitTestingWebAPI.Data; 10 | using UnitTestingWebAPI.Domain; 11 | 12 | namespace UnitTestingWebAPI.Tests 13 | { 14 | [TestFixture] 15 | public class MediaTypeFormatterTests 16 | { 17 | #region Variables 18 | Blog _blog; 19 | Article _article; 20 | ArticleFormatter _formatter; 21 | #endregion 22 | 23 | #region Setup 24 | [SetUp] 25 | public void Setup() 26 | { 27 | _blog = BloggerInitializer.GetBlogs().First(); 28 | _article = BloggerInitializer.GetChsakellsArticles().First(); 29 | _formatter = new ArticleFormatter(); 30 | } 31 | #endregion 32 | 33 | #region Tests 34 | [Test] 35 | public void FormatterShouldThrowExceptionWhenUnsupportedType() 36 | { 37 | Assert.Throws(() => new ObjectContent(_blog, _formatter)); 38 | } 39 | 40 | [Test] 41 | public void FormatterShouldNotThrowExceptionWhenArticle() 42 | { 43 | Assert.DoesNotThrow(() => new ObjectContent
(_article, _formatter)); 44 | } 45 | 46 | [Test] 47 | public void FormatterShouldHeaderBeSetCorrectly() 48 | { 49 | var content = new ObjectContent
(_article, new ArticleFormatter()); 50 | 51 | Assert.That(content.Headers.ContentType.MediaType, Is.EqualTo("application/article")); 52 | } 53 | 54 | [Test] 55 | public async void FormatterShouldBeAbleToDeserializeArticle() 56 | { 57 | var content = new ObjectContent
(_article, _formatter); 58 | 59 | var deserializedItem = await content.ReadAsAsync
(new[] { _formatter }); 60 | 61 | Assert.That(_article, Is.SameAs(deserializedItem)); 62 | } 63 | 64 | [Test] 65 | public void FormatterShouldNotBeAbleToWriteUnsupportedType() 66 | { 67 | var canWriteBlog = _formatter.CanWriteType(typeof(Blog)); 68 | Assert.That(canWriteBlog, Is.False); 69 | } 70 | 71 | [Test] 72 | public void FormatterShouldBeAbleToWriteArticle() 73 | { 74 | var canWriteArticle = _formatter.CanWriteType(typeof(Article)); 75 | Assert.That(canWriteArticle, Is.True); 76 | } 77 | #endregion 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/MessageHandlerTests.cs: -------------------------------------------------------------------------------- 1 | #region Using 2 | using Microsoft.Owin.Hosting; 3 | using Moq; 4 | using NUnit.Framework; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Net.Http; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using System.Web.Http; 13 | using UnitTestingWebAPI.API.Core.Controllers; 14 | using UnitTestingWebAPI.API.Core.MessageHandlers; 15 | using UnitTestingWebAPI.Data; 16 | using UnitTestingWebAPI.Data.Infrastructure; 17 | using UnitTestingWebAPI.Data.Repositories; 18 | using UnitTestingWebAPI.Domain; 19 | using UnitTestingWebAPI.Service; 20 | using UnitTestingWebAPI.Tests.Hosting; 21 | #endregion 22 | 23 | namespace UnitTestingWebAPI.Tests 24 | { 25 | [TestFixture] 26 | public class MessageHandlerTests 27 | { 28 | #region Variables 29 | private EndRequestHandler _endRequestHandler; 30 | private HeaderAppenderHandler _headerAppenderHandler; 31 | #endregion 32 | 33 | #region Setup 34 | [SetUp] 35 | public void Setup() 36 | { 37 | // Direct MessageHandler test 38 | _endRequestHandler = new EndRequestHandler(); 39 | _headerAppenderHandler = new HeaderAppenderHandler() 40 | { 41 | InnerHandler = _endRequestHandler 42 | }; 43 | } 44 | #endregion 45 | 46 | #region Tests 47 | [Test] 48 | public async void ShouldAppendCustomHeader() 49 | { 50 | var invoker = new HttpMessageInvoker(_headerAppenderHandler); 51 | var result = await invoker.SendAsync(new HttpRequestMessage(HttpMethod.Get, 52 | new Uri("http://localhost/api/test/")), CancellationToken.None); 53 | 54 | Assert.That(result.Headers.Contains("X-WebAPI-Header"), Is.True); 55 | Assert.That(result.Content.ReadAsStringAsync().Result, 56 | Is.EqualTo("Unit testing message handlers!")); 57 | } 58 | 59 | [Test] 60 | public void ShouldCallToControllerActionAppendCustomHeader() 61 | { 62 | //Arrange 63 | var address = "http://localhost:9000/"; 64 | 65 | using (WebApp.Start(address)) 66 | { 67 | HttpClient _client = new HttpClient(); 68 | var response = _client.GetAsync(address + "api/articles").Result; 69 | 70 | Assert.That(response.Headers.Contains("X-WebAPI-Header"), Is.True); 71 | 72 | var _returnedArticles = response.Content.ReadAsAsync>().Result; 73 | Assert.That(_returnedArticles.Count, Is.EqualTo( BloggerInitializer.GetAllArticles().Count)); 74 | } 75 | } 76 | #endregion 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnitTestingWebAPI.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnitTestingWebAPI.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0d2b4c59-fefa-4fdd-b4d6-0a94721c94b1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/RouteTests.cs: -------------------------------------------------------------------------------- 1 | #region Using 2 | using NUnit.Framework; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Net.Http; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Web.Http; 11 | using UnitTestingWebAPI.API.Core.Controllers; 12 | using UnitTestingWebAPI.Domain; 13 | using UnitTestingWebAPI.Tests.Helpers; 14 | #endregion 15 | 16 | namespace UnitTestingWebAPI.Tests 17 | { 18 | [TestFixture] 19 | public class RouteTests 20 | { 21 | #region Variables 22 | HttpConfiguration _config; 23 | #endregion 24 | 25 | #region Setup 26 | [SetUp] 27 | public void Setup() 28 | { 29 | _config = new HttpConfiguration(); 30 | _config.Routes.MapHttpRoute(name: "DefaultWebAPI", routeTemplate: "api/{controller}/{id}", 31 | defaults: new { id = RouteParameter.Optional }); 32 | } 33 | #endregion 34 | 35 | #region Tests 36 | [Test] 37 | public void RouteShouldControllerGetArticleIsInvoked() 38 | { 39 | var request = new HttpRequestMessage(HttpMethod.Get, "http://www.chsakell.com/api/articles/5"); 40 | 41 | var _actionSelector = new ControllerActionSelector(_config, request); 42 | 43 | Assert.That(typeof(ArticlesController), Is.EqualTo(_actionSelector.GetControllerType())); 44 | Assert.That(GetMethodName((ArticlesController c) => c.GetArticle(5)), 45 | Is.EqualTo(_actionSelector.GetActionName())); 46 | } 47 | 48 | [Test] 49 | public void RouteShouldPostArticleActionIsInvoked() 50 | { 51 | var request = new HttpRequestMessage(HttpMethod.Post, "http://www.chsakell.com/api/articles/"); 52 | 53 | var _actionSelector = new ControllerActionSelector(_config, request); 54 | 55 | Assert.That(GetMethodName((ArticlesController c) => 56 | c.PostArticle(new Article())), Is.EqualTo(_actionSelector.GetActionName())); 57 | } 58 | 59 | [Test] 60 | public void RouteShouldInvalidRouteThrowException() 61 | { 62 | var request = new HttpRequestMessage(HttpMethod.Post, "http://www.chsakell.com/api/InvalidController/"); 63 | 64 | var _actionSelector = new ControllerActionSelector(_config, request); 65 | 66 | Assert.Throws(() => _actionSelector.GetActionName()); 67 | } 68 | 69 | #endregion 70 | 71 | #region Helper methods 72 | public static string GetMethodName(Expression> expression) 73 | { 74 | var method = expression.Body as MethodCallExpression; 75 | if (method != null) 76 | return method.Method.Name; 77 | 78 | throw new ArgumentException("Expression is wrong"); 79 | } 80 | #endregion 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/ServicesTests.cs: -------------------------------------------------------------------------------- 1 | #region Using 2 | using Moq; 3 | using NUnit.Framework; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using UnitTestingWebAPI.Data; 10 | using UnitTestingWebAPI.Data.Infrastructure; 11 | using UnitTestingWebAPI.Data.Repositories; 12 | using UnitTestingWebAPI.Domain; 13 | using UnitTestingWebAPI.Service; 14 | #endregion 15 | 16 | namespace UnitTestingWebAPI.Tests 17 | { 18 | [TestFixture] 19 | public class ServicesTests 20 | { 21 | #region Variables 22 | IArticleService _articleService; 23 | IArticleRepository _articleRepository; 24 | IUnitOfWork _unitOfWork; 25 | List
_randomArticles; 26 | #endregion 27 | 28 | #region Setup 29 | [SetUp] 30 | public void Setup() 31 | { 32 | _randomArticles = SetupArticles(); 33 | 34 | _articleRepository = SetupArticleRepository(); 35 | _unitOfWork = new Mock().Object; 36 | _articleService = new ArticleService(_articleRepository, _unitOfWork); 37 | } 38 | 39 | public List
SetupArticles() 40 | { 41 | int _counter = new int(); 42 | List
_articles = BloggerInitializer.GetAllArticles(); 43 | 44 | foreach (Article _article in _articles) 45 | _article.ID = ++_counter; 46 | 47 | return _articles; 48 | } 49 | 50 | public IArticleRepository SetupArticleRepository() 51 | { 52 | // Init repository 53 | var repo = new Mock(); 54 | 55 | // Setup mocking behavior 56 | repo.Setup(r => r.GetAll()).Returns(_randomArticles); 57 | 58 | repo.Setup(r => r.GetById(It.IsAny())) 59 | .Returns(new Func( 60 | id => _randomArticles.Find(a => a.ID.Equals(id)))); 61 | 62 | repo.Setup(r => r.Add(It.IsAny
())) 63 | .Callback(new Action
(newArticle => 64 | { 65 | dynamic maxArticleID = _randomArticles.Last().ID; 66 | dynamic nextArticleID = maxArticleID + 1; 67 | newArticle.ID = nextArticleID; 68 | newArticle.DateCreated = DateTime.Now; 69 | _randomArticles.Add(newArticle); 70 | })); 71 | 72 | repo.Setup(r => r.Update(It.IsAny
())) 73 | .Callback(new Action
(x => 74 | { 75 | var oldArticle = _randomArticles.Find(a => a.ID == x.ID); 76 | oldArticle.DateEdited = DateTime.Now; 77 | oldArticle = x; 78 | })); 79 | 80 | repo.Setup(r => r.Delete(It.IsAny
())) 81 | .Callback(new Action
(x => 82 | { 83 | var _articleToRemove = _randomArticles.Find(a => a.ID == x.ID); 84 | 85 | if (_articleToRemove != null) 86 | _randomArticles.Remove(_articleToRemove); 87 | })); 88 | 89 | // Return mock implementation 90 | return repo.Object; 91 | } 92 | 93 | #endregion 94 | 95 | #region Tests 96 | [Test] 97 | public void ServiceShouldReturnAllArticles() 98 | { 99 | var articles = _articleService.GetArticles(); 100 | 101 | Assert.That(articles, Is.EqualTo(_randomArticles)); 102 | } 103 | 104 | [Test] 105 | public void ServiceShouldReturnRightArticle() 106 | { 107 | var wcfSecurityArticle = _articleService.GetArticle(2); 108 | 109 | Assert.That(wcfSecurityArticle, 110 | Is.EqualTo(_randomArticles.Find(a => a.Title.Contains("Secure WCF Services")))); 111 | } 112 | 113 | [Test] 114 | public void ServiceShouldAddNewArticle() 115 | { 116 | var _newArticle = new Article() 117 | { 118 | Author = "Chris Sakellarios", 119 | Contents = "If you are an ASP.NET MVC developer, you will certainly..", 120 | Title = "URL Rooting in ASP.NET (Web Forms)", 121 | URL = "http://chsakell.com/2013/12/15/url-rooting-in-asp-net-web-forms/" 122 | }; 123 | 124 | int _maxArticleIDBeforeAdd = _randomArticles.Max(a => a.ID); 125 | _articleService.CreateArticle(_newArticle); 126 | 127 | Assert.That(_newArticle, Is.EqualTo(_randomArticles.Last())); 128 | Assert.That(_maxArticleIDBeforeAdd + 1, Is.EqualTo(_randomArticles.Last().ID)); 129 | } 130 | 131 | [Test] 132 | public void ServiceShouldUpdateArticle() 133 | { 134 | var _firstArticle = _randomArticles.First(); 135 | 136 | _firstArticle.Title = "OData feat. ASP.NET Web API"; // reversed :-) 137 | _firstArticle.URL = "http://t.co/fuIbNoc7Zh"; // short link 138 | _articleService.UpdateArticle(_firstArticle); 139 | 140 | Assert.That(_firstArticle.DateEdited, Is.Not.EqualTo(DateTime.MinValue)); 141 | Assert.That(_firstArticle.URL, Is.EqualTo("http://t.co/fuIbNoc7Zh")); 142 | Assert.That(_firstArticle.ID, Is.EqualTo(1)); // hasn't changed 143 | } 144 | 145 | [Test] 146 | public void ServiceShouldDeleteArticle() 147 | { 148 | int maxID = _randomArticles.Max(a => a.ID); // Before removal 149 | var _lastArticle = _randomArticles.Last(); 150 | 151 | // Remove last article 152 | _articleService.DeleteArticle(_lastArticle); 153 | 154 | Assert.That(maxID, Is.GreaterThan(_randomArticles.Max(a => a.ID))); // Max reduced by 1 155 | } 156 | 157 | #endregion 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/UnitTestingWebAPI.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6A2CCFCC-5497-45B7-9C37-E944147817B9} 8 | Library 9 | Properties 10 | UnitTestingWebAPI.Tests 11 | UnitTestingWebAPI.Tests 12 | v4.5.1 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll 37 | 38 | 39 | ..\packages\Autofac.WebApi2.3.4.0\lib\net45\Autofac.Integration.WebApi.dll 40 | 41 | 42 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 43 | 44 | 45 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 46 | 47 | 48 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll 49 | 50 | 51 | ..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll 52 | 53 | 54 | ..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll 55 | 56 | 57 | ..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll 58 | 59 | 60 | False 61 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 62 | 63 | 64 | ..\packages\NUnit.2.6.4\lib\nunit.framework.dll 65 | 66 | 67 | ..\packages\Owin.1.0\lib\net40\Owin.dll 68 | 69 | 70 | 71 | 72 | 73 | 74 | False 75 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll 76 | 77 | 78 | False 79 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll 80 | 81 | 82 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll 83 | 84 | 85 | False 86 | ..\packages\Microsoft.AspNet.WebApi.SelfHost.5.2.3\lib\net45\System.Web.Http.SelfHost.dll 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | {04d7ae21-cabb-44a5-882c-44890aa19092} 108 | UnitTestingWebAPI.API.Core 109 | 110 | 111 | {d9166d82-be4e-4664-bbcc-7d31c274cb92} 112 | UnitTestingWebAPI.Data 113 | 114 | 115 | {004555f2-5b29-49d0-98fd-60d57e0de8aa} 116 | UnitTestingWebAPI.Domain 117 | 118 | 119 | {ea36fd16-a613-4f31-8bff-94ece2028a63} 120 | UnitTestingWebAPI.Service 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 135 | 136 | 137 | 138 | 145 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /UnitTestingWebAPI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestingWebAPI.Domain", "UnitTestingWebAPI.Domain\UnitTestingWebAPI.Domain.csproj", "{004555F2-5B29-49D0-98FD-60D57E0DE8AA}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestingWebAPI.Data", "UnitTestingWebAPI.Data\UnitTestingWebAPI.Data.csproj", "{D9166D82-BE4E-4664-BBCC-7D31C274CB92}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestingWebAPI.Service", "UnitTestingWebAPI.Service\UnitTestingWebAPI.Service.csproj", "{EA36FD16-A613-4F31-8BFF-94ECE2028A63}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestingWebAPI.API.Core", "UnitTestingWebAPI.API.Core\UnitTestingWebAPI.API.Core.csproj", "{04D7AE21-CABB-44A5-882C-44890AA19092}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestingWebAPI.API", "UnitTestingWebAPI.API\UnitTestingWebAPI.API.csproj", "{6D9E0639-885F-4B25-A5C4-1BEA8CF2F8C4}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestingWebAPI.Tests", "UnitTestingWebAPI.Tests\UnitTestingWebAPI.Tests.csproj", "{6A2CCFCC-5497-45B7-9C37-E944147817B9}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{7C5C5B36-EDA0-462C-87E8-9C70145078BD}" 19 | ProjectSection(SolutionItems) = preProject 20 | .nuget\NuGet.Config = .nuget\NuGet.Config 21 | .nuget\NuGet.exe = .nuget\NuGet.exe 22 | .nuget\NuGet.targets = .nuget\NuGet.targets 23 | EndProjectSection 24 | EndProject 25 | Global 26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 27 | Debug|Any CPU = Debug|Any CPU 28 | Release|Any CPU = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 31 | {004555F2-5B29-49D0-98FD-60D57E0DE8AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {004555F2-5B29-49D0-98FD-60D57E0DE8AA}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {004555F2-5B29-49D0-98FD-60D57E0DE8AA}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {004555F2-5B29-49D0-98FD-60D57E0DE8AA}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {D9166D82-BE4E-4664-BBCC-7D31C274CB92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {D9166D82-BE4E-4664-BBCC-7D31C274CB92}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {D9166D82-BE4E-4664-BBCC-7D31C274CB92}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {D9166D82-BE4E-4664-BBCC-7D31C274CB92}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {EA36FD16-A613-4F31-8BFF-94ECE2028A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {EA36FD16-A613-4F31-8BFF-94ECE2028A63}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {EA36FD16-A613-4F31-8BFF-94ECE2028A63}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {EA36FD16-A613-4F31-8BFF-94ECE2028A63}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {04D7AE21-CABB-44A5-882C-44890AA19092}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {04D7AE21-CABB-44A5-882C-44890AA19092}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {04D7AE21-CABB-44A5-882C-44890AA19092}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {04D7AE21-CABB-44A5-882C-44890AA19092}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {6D9E0639-885F-4B25-A5C4-1BEA8CF2F8C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {6D9E0639-885F-4B25-A5C4-1BEA8CF2F8C4}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {6D9E0639-885F-4B25-A5C4-1BEA8CF2F8C4}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {6D9E0639-885F-4B25-A5C4-1BEA8CF2F8C4}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {6A2CCFCC-5497-45B7-9C37-E944147817B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {6A2CCFCC-5497-45B7-9C37-E944147817B9}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {6A2CCFCC-5497-45B7-9C37-E944147817B9}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {6A2CCFCC-5497-45B7-9C37-E944147817B9}.Release|Any CPU.Build.0 = Release|Any CPU 55 | EndGlobalSection 56 | GlobalSection(SolutionProperties) = preSolution 57 | HideSolutionNode = FALSE 58 | EndGlobalSection 59 | EndGlobal 60 | -------------------------------------------------------------------------------- /licence: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 chsakell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | --------------------------------------------------------------------------------