Put interface behind database provider for testing. Use state object to get data from database, then map to model.
This commit is contained in:
parent
5a0d0933ce
commit
20ccdd07f1
11 changed files with 118 additions and 34 deletions
32
Website.Tests/Data/MySQLDatabaseProviderTests.cs
Normal file
32
Website.Tests/Data/MySQLDatabaseProviderTests.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using Website.Data;
|
||||||
|
using Xunit;
|
||||||
|
using FluentAssertions;
|
||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
using NSubstitute;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Website.Tests.Data
|
||||||
|
{
|
||||||
|
public class MySQLDatabaseProviderTests
|
||||||
|
{
|
||||||
|
const string ConnectionString = "Server=host;User ID=username;Password=password;Database=database";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewConnection_WithStringConstructor_ReturnsMySQLConnection() {
|
||||||
|
var provider = new MySQLDatabaseProvider(ConnectionString);
|
||||||
|
var connection = provider.NewConnection();
|
||||||
|
connection.Should().BeOfType<MySqlConnection>();
|
||||||
|
(connection as MySqlConnection).ConnectionString.Should().Be(ConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewConnection_WithConfigConstructor_ReturnsMySQLConnection() {
|
||||||
|
var config = Substitute.For<IConfiguration>();
|
||||||
|
config.GetConnectionString("database").Returns(ConnectionString);
|
||||||
|
var provider = new MySQLDatabaseProvider(ConnectionString);
|
||||||
|
var connection = provider.NewConnection();
|
||||||
|
connection.Should().BeOfType<MySqlConnection>();
|
||||||
|
(connection as MySqlConnection).ConnectionString.Should().Be(ConnectionString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,9 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="fluentassertions" Version="5.6.0" />
|
<PackageReference Include="fluentassertions" Version="5.6.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||||
|
<PackageReference Include="mysqlconnector" Version="0.52.0" />
|
||||||
<PackageReference Include="nsubstitute" Version="4.0.0" />
|
<PackageReference Include="nsubstitute" Version="4.0.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.0" />
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
|
|
|
@ -2,21 +2,22 @@ using System.Threading.Tasks;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using Website.Models;
|
using Website.Models;
|
||||||
|
using Website.Data.States;
|
||||||
|
|
||||||
namespace Website.Data
|
namespace Website.Data
|
||||||
{
|
{
|
||||||
public class BlogRepository
|
public class BlogRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseProvider _dbProvider;
|
private readonly IDatabaseProvider _dbProvider;
|
||||||
|
|
||||||
public BlogRepository(DatabaseProvider dbProvider) => _dbProvider = dbProvider;
|
public BlogRepository(IDatabaseProvider dbProvider) => _dbProvider = dbProvider;
|
||||||
|
|
||||||
public async Task<BlogPost> GetPostAsync(int id) {
|
public async Task<BlogPost> GetPostAsync(int id) {
|
||||||
const string query = "SELECT * FROM blog_posts WHERE post_id=@id";
|
const string query = "SELECT * FROM blog_posts WHERE post_id=@id AND post_deleted=0";
|
||||||
using (var connection = _dbProvider.NewConnection()) {
|
using (var connection = _dbProvider.NewConnection()) {
|
||||||
connection.Open();
|
connection.Open();
|
||||||
var result = await connection.QueryAsync<BlogPost>(query, new{id});
|
var result = await connection.QueryAsync<BlogPostState>(query, new{id});
|
||||||
return result.FirstOrDefault();
|
return new BlogPost(result.First());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
using System.Data;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
namespace Website.Data
|
|
||||||
{
|
|
||||||
public class DatabaseProvider
|
|
||||||
{
|
|
||||||
private readonly string _connectionString;
|
|
||||||
|
|
||||||
public DatabaseProvider(IConfiguration config) => _connectionString = config.GetConnectionString("database");
|
|
||||||
|
|
||||||
public DatabaseProvider(string connectionString) => _connectionString = connectionString;
|
|
||||||
|
|
||||||
public IDbConnection NewConnection() => new MySqlConnection(_connectionString);
|
|
||||||
}
|
|
||||||
}
|
|
9
Website/Data/IDatabaseProvider.cs
Normal file
9
Website/Data/IDatabaseProvider.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace Website.Data
|
||||||
|
{
|
||||||
|
public interface IDatabaseProvider
|
||||||
|
{
|
||||||
|
IDbConnection NewConnection();
|
||||||
|
}
|
||||||
|
}
|
17
Website/Data/MySQLDatabaseProvider.cs
Normal file
17
Website/Data/MySQLDatabaseProvider.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Data;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
|
||||||
|
namespace Website.Data
|
||||||
|
{
|
||||||
|
public class MySQLDatabaseProvider:IDatabaseProvider
|
||||||
|
{
|
||||||
|
private readonly string _connectionString;
|
||||||
|
|
||||||
|
public MySQLDatabaseProvider(IConfiguration config) => _connectionString = config.GetConnectionString("database");
|
||||||
|
|
||||||
|
public MySQLDatabaseProvider(string connectionString) => _connectionString = connectionString;
|
||||||
|
|
||||||
|
public IDbConnection NewConnection() => new MySqlConnection(_connectionString);
|
||||||
|
}
|
||||||
|
}
|
19
Website/Data/States/BlogPostState.cs
Normal file
19
Website/Data/States/BlogPostState.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using Dapper.Contrib.Extensions;
|
||||||
|
|
||||||
|
namespace Website.Data.States
|
||||||
|
{
|
||||||
|
[Table("blog_posts")]
|
||||||
|
public class BlogPostState
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int Post_Id { get; set; }
|
||||||
|
public string Post_Title { get; set; }
|
||||||
|
public string Post_Content { get; set; }
|
||||||
|
public DateTime Post_Timestamp { get; set; }
|
||||||
|
public string Post_Draft { get; set; }
|
||||||
|
public string Post_Url { get; set; }
|
||||||
|
public bool Post_Deleted{ get; set; }
|
||||||
|
public int User_Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using Website.Data.States;
|
||||||
|
|
||||||
namespace Website.Models
|
namespace Website.Models
|
||||||
{
|
{
|
||||||
public class BlogPost
|
public class BlogPost
|
||||||
{
|
{
|
||||||
public int PostId { get; set; }
|
public BlogPost(BlogPostState state)
|
||||||
public string PostTitle { get; set; }
|
{
|
||||||
public string Post_Title { get; set; }
|
Id = state.Post_Id;
|
||||||
|
Title = state.Post_Title;
|
||||||
|
Content = state.Post_Content;
|
||||||
|
Timestamp = state.Post_Timestamp;
|
||||||
|
Draft = state.Post_Draft;
|
||||||
|
Url = state.Post_Url;
|
||||||
|
UserId = state.User_Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
public string Draft { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public int UserId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,7 +39,7 @@ namespace Website
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterRepositories(IServiceCollection services) =>
|
private void RegisterRepositories(IServiceCollection services) =>
|
||||||
services.AddSingleton<DatabaseProvider, DatabaseProvider>()
|
services.AddSingleton<IDatabaseProvider, MySQLDatabaseProvider>()
|
||||||
.AddSingleton<BlogRepository, BlogRepository>();
|
.AddSingleton<BlogRepository, BlogRepository>();
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
ViewData["Title"] = "Blog";
|
ViewData["Title"] = "Blog";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model.PostTitle
|
@Model.Title
|
|
@ -5,5 +5,8 @@
|
||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"database": "Server=localhost;User ID=user;Password=pass;Database=db"
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue