Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ardalis committed Nov 16, 2023
2 parents 777ae62 + 762eb2e commit 41f3b1a
Show file tree
Hide file tree
Showing 19 changed files with 218 additions and 51 deletions.
35 changes: 35 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md.
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/src/Clean.Architecture.Web/bin/Debug/net7.0/Clean.Architecture.Web.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Clean.Architecture.Web",
"stopAtEntry": false,
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}
41 changes: 41 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Clean.Architecture.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/Clean.Architecture.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/Clean.Architecture.sln"
],
"problemMatcher": "$msCompile"
}
]
}
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-rc.2.23480.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0-rc.2.23480.1" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0-rc.2.23479.6" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0-rc.2.23509.1" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ Test projects could be organized based on the kind of test (unit, functional, in

- [xunit](https://www.nuget.org/packages/xunit) I'm using xunit because that's what ASP.NET Core uses internally to test the product. It works great and as new versions of ASP.NET Core ship, I'm confident it will continue to work well with it.

- [Moq](https://www.nuget.org/packages/Moq/) I'm using Moq as a mocking framework for white box behavior-based tests. If I have a method that, under certain circumstances, should perform an action that isn't evident from the object's observable state, mocks provide a way to test that. I could also use my own Fake implementation, but that requires a lot more typing and files. Moq is great once you get the hang of it, and assuming you don't have to mock the world (which we don't in this case because of good, modular design).
- [NSubstitute](https://www.nuget.org/packages/NSubstitute) I'm using NSubstitute as a mocking framework for white box behavior-based tests. If I have a method that, under certain circumstances, should perform an action that isn't evident from the object's observable state, mocks provide a way to test that. I could also use my own Fake implementation, but that requires a lot more typing and files. NSubstitute is great once you get the hang of it, and assuming you don't have to mock the world (which we don't in this case because of good, modular design).

- [Microsoft.AspNetCore.TestHost](https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost) I'm using TestHost to test my web project using its full stack, not just unit testing action methods. Using TestHost, you make actual HttpClient requests without going over the wire (so no firewall or port configuration issues). Tests run in memory and are very fast, and requests exercise the full MVC stack, including routing, model binding, model validation, filters, etc.

Expand Down
2 changes: 1 addition & 1 deletion sample/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<NoWarn>1591</NoWarn> <!-- Remove this to turn on warnings for missing XML Comments -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace NimblePros.SampleToDo.Infrastructure;
public class AutofacInfrastructureModule : Module
{
private readonly bool _isDevelopment = false;
private readonly List<Assembly> _assemblies = new List<Assembly>();
private readonly List<Assembly> _assemblies = [];

public AutofacInfrastructureModule(bool isDevelopment, Assembly? callingAssembly = null)
{
Expand Down Expand Up @@ -102,7 +102,7 @@ private void RegisterMediatR(ContainerBuilder builder)
foreach (var mediatrOpenType in mediatrOpenTypes)
{
builder
.RegisterAssemblyTypes(_assemblies.ToArray())
.RegisterAssemblyTypes([.. _assemblies])
.AsClosedTypesOf(mediatrOpenType)
.AsImplementedInterfaces();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,14 @@

namespace NimblePros.SampleToDo.Infrastructure.Data.Queries;

public class ListProjectsShallowQueryService : IListProjectsShallowQueryService
public class ListProjectsShallowQueryService(AppDbContext db) :
IListProjectsShallowQueryService
{
private readonly AppDbContext _db;

public ListProjectsShallowQueryService(AppDbContext db)
{
_db = db;
}
private readonly AppDbContext _db = db;

public async Task<IEnumerable<ProjectDTO>> ListAsync()
{
var result = await _db.Projects.FromSqlRaw("SELECT Id, Name, Status FROM Projects") // don't fetch other big columns
var result = await _db.Projects.FromSqlRaw("SELECT Id, Name FROM Projects") // don't fetch other big columns
.Select(x => new ProjectDTO(x.Id, x.Name, x.Status.ToString()))
.ToListAsync();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@

namespace NimblePros.SampleToDo.UseCases.Projects.ListShallow;

public class ListProjectsShallowHandler : IQueryHandler<ListProjectsShallowQuery, Result<IEnumerable<ProjectDTO>>>
public class ListProjectsShallowHandler(IListProjectsShallowQueryService query)
: IQueryHandler<ListProjectsShallowQuery, Result<IEnumerable<ProjectDTO>>>
{
private readonly IListProjectsShallowQueryService _query;

public ListProjectsShallowHandler(IListProjectsShallowQueryService query)
{
_query = query;
}
private readonly IListProjectsShallowQueryService _query = query;

public async Task<Result<IEnumerable<ProjectDTO>>> Handle(ListProjectsShallowQuery request, CancellationToken cancellationToken)
{
Expand Down
61 changes: 61 additions & 0 deletions sample/src/NimblePros.SampleToDo.Web/api.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# For more info on HTTP files go to https://aka.ms/vs/httpfile
@hostname=localhost
@port=57678

// List all contributors
GET http://{{hostname}}:{{port}}/Contributors

###

// Get a specific contributor
@id_to_get=1
GET http://{{hostname}}:{{port}}/Contributors/{{id_to_get}}

###

// Add a new contributor
POST http://{{hostname}}:{{port}}/Contributors
Content-Type: application/json

{
"name": "John Doe"
}

###

// Update a contributor
@id_to_update=1
PUT http://{{hostname}}:{{port}}/Contributors/{{id_to_update}}
Content-Type: application/json

{
"id": {{id_to_update}},
"name": "ardalis2"
}

###

// Delete a contributor
@id_to_delete=1
DELETE http://{{hostname}}:{{port}}/Contributors/{{id_to_delete}}

###

// List all Projects
GET http://{{hostname}}:{{port}}/Projects

###

// Get a specific project
@id_to_get=1
GET http://{{hostname}}:{{port}}/Projects/{{id_to_get}}

###

// Create a new project
POST http://{{hostname}}:{{port}}/Projects
Content-Type: application/json

{
"name": "New Project"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<Sdk Name="Microsoft.Build.CentralPackageVersions" Version="2.1.3" />

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<Sdk Name="Microsoft.Build.CentralPackageVersions" Version="2.1.3" />

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<Sdk Name="Microsoft.Build.CentralPackageVersions" Version="2.1.3" />

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ private void RegisterEF(ContainerBuilder builder)

private void RegisterQueries(ContainerBuilder builder)
{
builder.RegisterType<ListContributorsQueryService>()
.As<IListContributorsQueryService>()
.InstancePerLifetimeScope();
}

private void RegisterMediatR(ContainerBuilder builder)
Expand Down Expand Up @@ -117,19 +120,15 @@ private void RegisterDevelopmentOnlyDependencies(ContainerBuilder builder)
builder.RegisterType<FakeEmailSender>().As<IEmailSender>()
.InstancePerLifetimeScope();

builder.RegisterType<FakeListContributorsQueryService>()
.As<IListContributorsQueryService>()
.InstancePerLifetimeScope();
//builder.RegisterType<FakeListContributorsQueryService>()
// .As<IListContributorsQueryService>()
// .InstancePerLifetimeScope();
}

private void RegisterProductionOnlyDependencies(ContainerBuilder builder)
{
// NOTE: Add any production only (real) services here
builder.RegisterType<SmtpEmailSender>().As<IEmailSender>()
.InstancePerLifetimeScope();

builder.RegisterType<ListContributorsQueryService>()
.As<IListContributorsQueryService>()
.InstancePerLifetimeScope();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ public class FakeListContributorsQueryService : IListContributorsQueryService
{
public Task<IEnumerable<ContributorDTO>> ListAsync()
{
var result = new List<ContributorDTO>() { new ContributorDTO(1, "Ardalis"), new ContributorDTO(2, "Snowfrog") };
List<ContributorDTO> result =
[new ContributorDTO(1, "Fake Contributor 1"),
new ContributorDTO(2, "Fake Contributor 2")];

return Task.FromResult(result.AsEnumerable());
}
}
4 changes: 2 additions & 2 deletions src/Clean.Architecture.Web/Clean.Architecture.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
<PackageReference Include="Ardalis.Result" />
<PackageReference Include="Ardalis.Result.AspNetCore" />
<PackageReference Include="FastEndpoints" />
<PackageReference Include="FastEndpoints.ApiExplorer" />
<!--<PackageReference Include="FastEndpoints.ApiExplorer" />-->
<PackageReference Include="FastEndpoints.Swagger" />
<PackageReference Include="FastEndpoints.Swagger.Swashbuckle" />
<!-- <PackageReference Include="FastEndpoints.Swagger.Swashbuckle" />-->
<PackageReference Include="MediatR" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" PrivateAssets="All" />
Expand Down
29 changes: 13 additions & 16 deletions src/Clean.Architecture.Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,20 @@

static void SeedDatabase(WebApplication app)
{
// Seed Database
using (var scope = app.Services.CreateScope())
using var scope = app.Services.CreateScope();
var services = scope.ServiceProvider;

try
{
var context = services.GetRequiredService<AppDbContext>();
// context.Database.Migrate();
context.Database.EnsureCreated();
SeedData.Initialize(services);
}
catch (Exception ex)
{
var services = scope.ServiceProvider;

try
{
var context = services.GetRequiredService<AppDbContext>();
// context.Database.Migrate();
context.Database.EnsureCreated();
SeedData.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB. {exceptionMessage}", ex.Message);
}
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB. {exceptionMessage}", ex.Message);
}
}

Expand Down
42 changes: 42 additions & 0 deletions src/Clean.Architecture.Web/api.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# For more info on HTTP files go to https://aka.ms/vs/httpfile
@hostname=localhost
@port=57679

// List all contributors
GET http://{{hostname}}:{{port}}/Contributors

###

// Get a specific contributor
@id_to_get=1
GET http://{{hostname}}:{{port}}/Contributors/{{id_to_get}}

###

// Add a new contributor
POST http://{{hostname}}:{{port}}/Contributors
Content-Type: application/json

{
"name": "John Doe",
"email": "[email protected]"
}

###

// Update a contributor
@id_to_update=1
PUT http://{{hostname}}:{{port}}/Contributors/{{id_to_update}}
Content-Type: application/json

{
"id": {{id_to_update}},
"name": "ardalis2"
}

###

// Delete a contributor
@id_to_delete=1
DELETE http://{{hostname}}:{{port}}/Contributors/{{id_to_delete}}

Loading

0 comments on commit 41f3b1a

Please sign in to comment.