From fcdec6686180a29e98d0c7f921df896d6ad82dc0 Mon Sep 17 00:00:00 2001 From: Robert Marshall Date: Mon, 13 Apr 2020 13:01:14 +0100 Subject: [PATCH] Test blog controller --- .../Controllers/BlogControllerTests.cs | 177 ++++++++++++++++++ src/Website/Controllers/BlogController.cs | 7 +- 2 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 src/Website.Tests/Controllers/BlogControllerTests.cs diff --git a/src/Website.Tests/Controllers/BlogControllerTests.cs b/src/Website.Tests/Controllers/BlogControllerTests.cs new file mode 100644 index 0000000..e4f9ff3 --- /dev/null +++ b/src/Website.Tests/Controllers/BlogControllerTests.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.AspNetCore.Mvc; +using NSubstitute; +using NSubstitute.ExceptionExtensions; +using Website.Controllers; +using Website.Data; +using Website.Models.Blog; +using Website.ViewModels.Blog; +using Xunit; + +namespace Website.Tests.Controllers { + public class BlogControllerTests { + [Fact] + public async Task Page_WithPageNumber_ReturnsViewWithBlogPosts() { + var api = Substitute.For(); + api.GetLatestPostsAsync(10, 10).Returns(new[] { new BlogPost { Content = "" } }); + api.GetCountAsync().Returns(30); + + var controller = new BlogController(api); + + var expectation = new[] { new BlogPostSnippetViewModel(new BlogPost { Content = "" }) }; + + var model = (await controller.Page(2) as ViewResult).Model as BlogViewModel; + model.Page.Should().Be(2); + model.MaxPages.Should().Be(3); + model.Posts.Should().BeEquivalentTo(expectation); + } + + [Fact] + public async Task Entry_WithUrlThatExists_ForPostWithContent_ReturnsViewWithBlogPost() { + var api = Substitute.For(); + api.GetPostByUrlAsync("url").Returns(new BlogPost { Content = "c" }); + + var expectation = new BlogPostViewModel(new BlogPost { Content = "c" }, false); + + var controller = new BlogController(api); + var result = await controller.Entry("url"); + result.Should().BeOfType(); + (result as ViewResult).Model.Should().BeEquivalentTo(expectation); + } + + [Fact] + public async Task Entry_WithUrlThatExists_ForPostWithoutContent_Returns404() { + var api = Substitute.For(); + api.GetPostByUrlAsync("url").Returns(new BlogPost()); + + var controller = new BlogController(api); + (await controller.Entry("url")).Should().BeOfType(); + } + + [Fact] + public async Task Entry_WithUrlThatExistsAndPreview_ForPostWithoutContent_ReturnsViewWithBlogPost() { + var api = Substitute.For(); + api.GetPostByUrlAsync("url").Returns(new BlogPost { Draft = "" }); + + var expectation = new BlogPostViewModel(new BlogPost { Draft = "" }, true); + + var controller = new BlogController(api); + var result = await controller.Entry("url", true); + result.Should().BeOfType(); + (result as ViewResult).Model.Should().BeEquivalentTo(expectation); + } + + [Fact] + public async Task Entry_WithUrlThatDoesntExist_Returns404() { + var api = Substitute.For(); + api.GetPostByUrlAsync("url") + .Throws(new ApiCallException(new HttpResponseMessage(HttpStatusCode.NotFound) { + RequestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri("http://example.com/")) + })); + + var controller = new BlogController(api); + (await controller.Entry("url")).Should().BeOfType(); + } + + [Fact] + public async Task Edit_WithIdThatExists_ReturnsViewWithBlogPostSubmission() { + var api = Substitute.For(); + api.GetPostByIdAsync(1).Returns(new BlogPost()); + + var expectation = new BlogPostSubmission { + Id = 0 + }; + + var controller = new BlogController(api); + var result = await controller.Edit(1); + result.Should().BeOfType(); + (result as ViewResult).Model.Should().BeEquivalentTo(expectation); + } + + [Fact] + public async Task Edit_WithIdThatDoesntExist_Returns404() { + var api = Substitute.For(); + api.GetPostByIdAsync(1) + .Throws(new ApiCallException(new HttpResponseMessage(HttpStatusCode.NotFound) { + RequestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri("http://example.com/")) + })); + + var controller = new BlogController(api); + (await controller.Edit(1)).Should().BeOfType(); + } + + [Fact] + public async Task Edit_WithNullId_ReturnsEmptyView() { + var api = Substitute.For(); + + var controller = new BlogController(api); + var result = await controller.Edit(null); + result.Should().BeOfType(); + (result as ViewResult).Model.Should().BeNull(); + } + + [Fact] + public async Task Save_WithSubmission_SavesPostAndRedirectsToEditPage() { + var api = Substitute.For(); + + var submission = new BlogPostSubmission(); + api.SavePost(submission).Returns(new BlogPost { Id = 1 }); + + var controller = new BlogController(api); + var result = await controller.Save(submission); + result.Should().BeOfType(); + (result as RedirectToActionResult).ActionName.Should().Be("Edit"); + (result as RedirectToActionResult).RouteValues.Should().Contain(new KeyValuePair("id", 1)); + } + + + [Fact] + public async Task Manage_ReturnsViewWithBlogPostsOrderedByDateDescending() { + var api = Substitute.For(); + var posts = new[] { + new BlogPost{Timestamp = new DateTime(2020, 1, 2), Content= ""}, + new BlogPost{Timestamp = new DateTime(2020, 1, 3), Content= ""}, + new BlogPost{Timestamp = new DateTime(2020, 1, 1), Content= ""} + }; + api.GetAllPostsAsync().Returns(posts); + + var expectation = new[] { + new BlogPostViewModel(new BlogPost{Timestamp = new DateTime(2020, 1, 3), Content = ""}, false), + new BlogPostViewModel(new BlogPost{Timestamp = new DateTime(2020, 1, 2), Content = ""}, false), + new BlogPostViewModel(new BlogPost{Timestamp = new DateTime(2020, 1, 1), Content = ""}, false) + }; + + var controller = new BlogController(api); + var result = await controller.Manage(); + result.Should().BeOfType(); + (result as ViewResult).Model.Should().BeEquivalentTo(expectation); + } + + [Fact] + public async Task Publish_WithId_PublishesPostAndRedirectsToManagePage() { + var api = Substitute.For(); + + var controller = new BlogController(api); + var result = await controller.Publish(1); + await api.Received(1).PublishPostAsync(1); + result.Should().BeOfType(); + (result as RedirectToActionResult).ActionName.Should().Be("Manage"); + } + + [Fact] + public async Task Delete_WithId_DeletesPostAndRedirectsToManagePage() { + var api = Substitute.For(); + + var controller = new BlogController(api); + var result = await controller.Delete(1); + await api.Received(1).DeletePostAsync(1); + result.Should().BeOfType(); + (result as RedirectToActionResult).ActionName.Should().Be("Manage"); + } + } +} \ No newline at end of file diff --git a/src/Website/Controllers/BlogController.cs b/src/Website/Controllers/BlogController.cs index cb59930..51ff056 100644 --- a/src/Website/Controllers/BlogController.cs +++ b/src/Website/Controllers/BlogController.cs @@ -1,5 +1,4 @@ -using System; -using System.Linq; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -31,7 +30,7 @@ namespace Website.Controllers { var model = new BlogPostViewModel(post, preview); return View(model); - } catch (InvalidOperationException) { + } catch (ApiCallException) { return NotFound(); } } @@ -49,7 +48,7 @@ namespace Website.Controllers { Content = post.Draft }; return View(model); - } catch (InvalidOperationException) { + } catch (ApiCallException) { return NotFound(); } }