Add tests for controller. Put in contigency for when an item isn't found.
This commit is contained in:
parent
a22f8b125c
commit
c0c1311a0a
6 changed files with 119 additions and 11 deletions
52
src/Robware.Api.Blog.Tests/BlogControllerTests.cs
Normal file
52
src/Robware.Api.Blog.Tests/BlogControllerTests.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ExceptionExtensions;
|
||||
using Robware.Api.Blog.Controllers;
|
||||
using Robware.Blog;
|
||||
using Robware.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Robware.Api.Blog.Tests {
|
||||
public class BlogControllerTests {
|
||||
[Fact]
|
||||
public async Task Get_WithUrl_ReturnsBlogPost() {
|
||||
var logger = Substitute.For<ILogger<BlogController>>();
|
||||
var repo = Substitute.For<IBlogRepository>();
|
||||
|
||||
repo.GetPostByUrlAsync("url").Returns(new BlogPost());
|
||||
|
||||
var expectation = new BlogPost();
|
||||
|
||||
var controller = new BlogController(logger, repo);
|
||||
(await controller.Get("url")).Value.Should().BeEquivalentTo(expectation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_WithId_ReturnsBlogPost() {
|
||||
var logger = Substitute.For<ILogger<BlogController>>();
|
||||
var repo = Substitute.For<IBlogRepository>();
|
||||
|
||||
repo.GetPostByIdAsync(1).Returns(new BlogPost());
|
||||
|
||||
var expectation = new BlogPost();
|
||||
|
||||
var controller = new BlogController(logger, repo);
|
||||
(await controller.Get("1")).Value.Should().BeEquivalentTo(expectation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_WithInvalidUrl_Returns404() {
|
||||
var logger = Substitute.For<ILogger<BlogController>>();
|
||||
var repo = Substitute.For<IBlogRepository>();
|
||||
|
||||
repo.GetPostByUrlAsync("url").Throws(new ItemNotFoundException("", null));
|
||||
|
||||
var controller = new BlogController(logger, repo);
|
||||
(await controller.Get("url")).Result.Should().BeOfType<NotFoundObjectResult>();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
22
src/Robware.Api.Blog.Tests/Robware.Api.Blog.Tests.csproj
Normal file
22
src/Robware.Api.Blog.Tests/Robware.Api.Blog.Tests.csproj
Normal file
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NSubstitute" Version="4.2.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Robware.Api.Blog\Robware.Api.Blog.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
..\.editorconfig = ..\.editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robware.Api.Blog.Tests", "Robware.Api.Blog.Tests\Robware.Api.Blog.Tests.csproj", "{54DEC274-5F28-42FB-9B60-1E4BAF3D7BF9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -38,6 +40,10 @@ Global
|
|||
{EEB41C17-B61C-451A-9C72-2B405DC42743}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EEB41C17-B61C-451A-9C72-2B405DC42743}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EEB41C17-B61C-451A-9C72-2B405DC42743}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{54DEC274-5F28-42FB-9B60-1E4BAF3D7BF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{54DEC274-5F28-42FB-9B60-1E4BAF3D7BF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{54DEC274-5F28-42FB-9B60-1E4BAF3D7BF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{54DEC274-5F28-42FB-9B60-1E4BAF3D7BF9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Robware.Blog;
|
||||
using Robware.Data;
|
||||
|
||||
namespace Robware.Api.Blog.Controllers {
|
||||
[ApiController]
|
||||
|
@ -16,15 +17,21 @@ namespace Robware.Api.Blog.Controllers {
|
|||
}
|
||||
|
||||
[HttpGet(nameof(Get) + "/{url}")]
|
||||
public async Task<BlogPost> Get(string url) {
|
||||
public async Task<ActionResult<BlogPost>> Get(string url) {
|
||||
_logger.Log(LogLevel.Information, $"{nameof(Get)}: {nameof(url)}={url}");
|
||||
|
||||
try {
|
||||
if (int.TryParse(url, out int id)) {
|
||||
return await _blogRepository.GetPostByIdAsync(id);
|
||||
}
|
||||
|
||||
return await _blogRepository.GetPostByUrlAsync(url);
|
||||
}
|
||||
catch (ItemNotFoundException e) {
|
||||
_logger.Log(LogLevel.Error, e.Message);
|
||||
return NotFound("Could not find blog post");
|
||||
}
|
||||
}
|
||||
|
||||
//[HttpGet]
|
||||
//Task<BlogPost> GetPostByUrl();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
|
@ -23,11 +24,20 @@ namespace Robware.Data
|
|||
UserId = state.User_Id
|
||||
};
|
||||
|
||||
private async Task<IEnumerable<T>> DoQuery<T>(IDbConnection connection, string query, object param = null) {
|
||||
var result = await connection.QueryAsync<T>(query, param);
|
||||
|
||||
if (!result.Any())
|
||||
throw new ItemNotFoundException(query, param);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<BlogPost> GetPostByUrlAsync(string url) {
|
||||
const string query = "SELECT * FROM blog_posts WHERE post_url=@url AND post_deleted=0";
|
||||
using (var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<BlogPostState>(query, new{url});
|
||||
var result = await DoQuery<BlogPostState>(connection, query, new{url});
|
||||
return MapBlogPost(result.First());
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +46,7 @@ namespace Robware.Data
|
|||
const string query = "SELECT * FROM blog_posts WHERE post_content<>'' AND post_deleted=0 ORDER BY post_timestamp DESC LIMIT @offset,@limit";
|
||||
using (var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var results = await connection.QueryAsync<BlogPostState>(query, new{limit, offset});
|
||||
var results = await DoQuery<BlogPostState>(connection, query, new{limit, offset});
|
||||
return results.Select(MapBlogPost);
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +58,7 @@ namespace Robware.Data
|
|||
var query="SELECT COUNT(*) FROM blog_posts WHERE post_content<>'' AND post_deleted=0";
|
||||
using(var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<int>(query);
|
||||
var result = await DoQuery<int>(connection, query);
|
||||
return result.First();
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +67,7 @@ namespace Robware.Data
|
|||
const string query = "SELECT * FROM blog_posts WHERE post_id=@id AND post_deleted=0";
|
||||
using (var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<BlogPostState>(query, new {id});
|
||||
var result = await DoQuery<BlogPostState>(connection, query, new {id});
|
||||
return MapBlogPost(result.First());
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +80,7 @@ namespace Robware.Data
|
|||
|
||||
using (var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<int>(newPost ? newPostQuery : updatePostQuery, post);
|
||||
var result = await DoQuery<int>(connection, newPost ? newPostQuery : updatePostQuery, post);
|
||||
return newPost ? await GetPostByIdAsync(result.Single()) : post;
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +90,7 @@ namespace Robware.Data
|
|||
|
||||
using (var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<BlogPostState>(query);
|
||||
var result = await DoQuery<BlogPostState>(connection, query);
|
||||
return result.Select(MapBlogPost);
|
||||
}
|
||||
}
|
||||
|
|
11
src/Robware.Data/ItemNotFoundException.cs
Normal file
11
src/Robware.Data/ItemNotFoundException.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Robware.Data {
|
||||
public class ItemNotFoundException:Exception {
|
||||
public object Parameters { get; }
|
||||
|
||||
public ItemNotFoundException(string query, object parameters):base($"Could not find an item for the query: {query}") {
|
||||
Parameters = parameters;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue