Skip to content

Commit

Permalink
Update content
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikko Miu committed Sep 14, 2024
1 parent 5d130d4 commit dc302f5
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 43 deletions.
14 changes: 7 additions & 7 deletions content/guides/dotnet-core-mongo/01-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ dotnet new apicontroller -o ./src/Monget.API/Controllers/ -n PropertiesControlle
Let's update the newly added controller to have our CRUD operations just return some simple strings for now. This will
let us build up the controller as we go:

```cs {file="src/Monget.API/Controllers/PropertiesController.cs"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs"}
namespace Monget.API.Controllers;

using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -136,7 +136,7 @@ public class PropertiesController : ControllerBase
Now, let's update the `Program.cs` to add support for controllers, remove the default weather route, as well as move
`UseHttpsRedirection()` under an `IsProduction()` check. With all of these changes your `Program.cs` should look like:

```cs {file="src/Monget.API/Program.cs"}
```c# {file="src/Monget.API/Program.cs"}
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
Expand Down Expand Up @@ -209,7 +209,7 @@ logic.
Let's create our `PropertyService` in our `Domain` project with just a simple placeholder return value for now (later
we are going to replace this with meaningful data to return):

```cs {file="src/Monget.Domain/Services/PropertyService.cs"}
```c# {file="src/Monget.Domain/Services/PropertyService.cs"}
namespace Monget.Domain.Services;

using Monget.Domain.Interfaces;
Expand All @@ -230,7 +230,7 @@ by defining the methods that need to be implmented for a given service.

With this in mind, let's create our `IPropertyService` in the `Interfaces` of the `Domain` project:

```cs {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
```c# {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
namespace Monget.Domain.Interfaces;

public interface IPropertyService
Expand All @@ -246,7 +246,7 @@ is an interface and not a class.

Now that we have created the interface we can tell our service that it implements this new interface:

```cs {file="src/Monget.Domain/Services/PropertyService.cs",add_lines=4,rem_lines=3}
```c# {file="src/Monget.Domain/Services/PropertyService.cs",add_lines=4,rem_lines=3}
namespace Monget.Domain.Services;

public class PropertyService
Expand All @@ -269,7 +269,7 @@ request, user, or other context data within our service we would need to use a d

So with this, let's update our `Program.cs` to inject our service:

```cs {file="src/Monget.API/Program.cs",add_lines="1-2 6-7"}
```c# {file="src/Monget.API/Program.cs",add_lines="1-2 6-7"}
using Monget.Domain.Interfaces;
using Monget.Domain.Services;

Expand All @@ -287,7 +287,7 @@ into our controller.

Add a constructor to the controller and let's call our `ListProperties()` method within our `List()` controller action:

```cs {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="7 9-12 17-19",rem_lines="20"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="7 9-12 17-19",rem_lines="20"}
namespace Monget.API.Controllers;

[Route("api/[controller]")]
Expand Down
36 changes: 18 additions & 18 deletions content/guides/dotnet-core-mongo/02-mongodb-and-property-crud.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ We need to create a class that will house the configuration for our database. Th
the `appsettings.json`, `appsettings.{Environment}.json`, as well as environment variables. Because this configuration
is part of the database, which is a part of the `Domain`, I'm going to be putting it in the `Domain` project:

```cs {file="src/Monget.Domain/Models/DatabaseSettings.cs"}
```c# {file="src/Monget.Domain/Models/DatabaseSettings.cs"}
namespace Monget.Domain.Models;

using MongoDB.Bson.Serialization.Conventions;
Expand Down Expand Up @@ -100,7 +100,7 @@ the recommended naming format for collections and fields on our database.
Now that the class is created for our configuration, we can tell the API to load this configuration from its sources in
the `Program.cs` of the `API` project:

```cs {file="src/Monget.API/Program.cs"}
```c# {file="src/Monget.API/Program.cs"}
// Add MongoDB Settings
builder.Services.Configure<DatabaseSettings>(builder.Configuration.GetSection(DatabaseSettings.SectionName));
builder.Services.AddSingleton(s => s.GetRequiredService<IOptions<DatabaseSettings>>().Value);
Expand Down Expand Up @@ -148,7 +148,7 @@ documentation.

## Create Domain Model

```cs {file="src/Monget.Domain/Models/Property.cs"}
```c# {file="src/Monget.Domain/Models/Property.cs"}
namespace Monget.Domain.Models;

using MongoDB.Bson;
Expand All @@ -173,7 +173,7 @@ public class Property
With our DI capable of loading the configuration from various sources, let's update the `PropertyService` to take in our
configuration and set some class level variables that we can use to access our collection.

```cs {file="src/Monget.Domain/Services/PropertyService.cs"}
```c# {file="src/Monget.Domain/Services/PropertyService.cs"}
namespace Monget.Domain.Services;

using Monget.Domain.Interfaces;
Expand Down Expand Up @@ -205,7 +205,7 @@ public class PropertyService : IPropertyService
Since we are changing the method name (to `ListPropertiesAsync`), and the return type of `ListProperties` we need to
update the interface to match our new contract:

```cs {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
```c# {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
namespace Monget.Domain.Interfaces;

using Monget.Domain.Models;
Expand All @@ -228,7 +228,7 @@ For right now, we are just going to convert our API method to be `async` returni
response set to the database model. After we complete the `CreateAsync` we will return our API model instead of directly
returning the database model.

```cs {file="src/Monget.API/Controllers/PropertiesController.cs"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs"}
[HttpGet]
public async Task<ActionResult> ListAsync(int size = 24, int skip = 0)
{
Expand All @@ -247,7 +247,7 @@ Let's update `Create` to be `CreateAsync` and create a new property in our datab
a few different places (`IPropertyService`, `PropertyService`, and `PropertiesController`). Let's start with the service
interface:

```cs {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
```c# {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
namespace Monget.Domain.Interfaces;

using Monget.Domain.Models;
Expand All @@ -261,7 +261,7 @@ public interface IPropertyService

Now that we have our interface updated, we can implement the interface on our service:

```cs {file="src/Monget.Domain/Services/PropertyService.cs"}
```c# {file="src/Monget.Domain/Services/PropertyService.cs"}
public async Task<Property> CreatePropertyAsync(Property property)
{
var newProperty = new Property {
Expand Down Expand Up @@ -292,7 +292,7 @@ Finally, we just need to update our `Create` method on the controller to be `asy
parse our request body from JSON into the model for us and even provide us with the ability to automatically validate
the request from the user (more on this later).

```cs {file="src/Monget.API/Controllers/PropertiesController.cs"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs"}
[HttpPost]
public async Task<ActionResult> CreateAsync([FromBody] Property property)
{
Expand All @@ -318,7 +318,7 @@ computed or not user-exposed.

Now we can create our API models. The first model we can create is the `PropertyRequest` model:

```cs {file="src/Monget.Models/PropertyRequest.cs"}
```c# {file="src/Monget.Models/PropertyRequest.cs"}
namespace Monget.Models;

using System.ComponentModel.DataAnnotations;
Expand All @@ -343,7 +343,7 @@ data _before_ we proceed to the controller actions for each of them.
We also need to create the `PropertyResponse` model. This model will be the model for returning a single instance of a
`Property` from our API back to the clients.

```cs {file="src/Monget.Models/PropertyResponse.cs"}
```c# {file="src/Monget.Models/PropertyResponse.cs"}
namespace Monget.Models;

public class PropertyResponse
Expand Down Expand Up @@ -378,7 +378,7 @@ dotnet add ./src/Monget.API/Monget.API.csproj package AutoMapper.Extensions.Micr
This will add the `AutoMapper` package as well as the necessary extensions for DI within ASP.NET. Then, we need to add
our mapper class:

```cs {file="src/Monget.API/MappingProfile.cs"}
```c# {file="src/Monget.API/MappingProfile.cs"}
namespace Monget.API;

using AutoMapper;
Expand All @@ -398,7 +398,7 @@ public class MappingProfile : Profile
Next, we can add `AutoMapper` to the DI within our `Program.cs` to manage model mappings for us. I generally place this
after the `Configure()` calls and before any service instances:

```cs {file="src/Monget.API/Program.cs"}
```c# {file="src/Monget.API/Program.cs"}
// Add AutoMapper
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
```
Expand All @@ -407,7 +407,7 @@ With AutoMapper added to our application's DI, we can add it to our controller.
`IMapper` parameter to the constructor of our controller. This will allow us to map between types using the
`Map<TDestination>()` method:

```cs {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="3 6 8 13 18 23 26-28 31",rem_lines="14 19 24 29 32"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="3 6 8 13 18 23 26-28 31",rem_lines="14 19 24 29 32"}
public class PropertiesController : ControllerBase
{
private readonly IMapper _mapper;
Expand Down Expand Up @@ -473,7 +473,7 @@ and 100. Also, we'll set a `[Range(0, int.MaxValue)]` attribute on the `skip` pa
the highest value that will fit into an `int`. This is to make sure someone doesn't pass a negative value as well as
making sure that someone doesn't accidently pass a value that will overflow the `int`.

```cs {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines=2,rem_lines=1}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines=2,rem_lines=1}
public async Task<ActionResult<PropertyResponse>> ListAsync(int size = 24, int skip = 0)
public async Task<ActionResult<PropertyResponse>> ListAsync([Range(1, 100)] int size = 24, [Range(0, int.MaxValue)] int skip = 0)
```
Expand All @@ -482,7 +482,7 @@ public async Task<ActionResult<PropertyResponse>> ListAsync([Range(1, 100)] int

Starting with the service this time, let's create the methods needed to complete our CRUD operations:

```cs {file="src/Monget.Domain/Services/PropertyService.cs"}
```c# {file="src/Monget.Domain/Services/PropertyService.cs"}
public Task<Property> GetPropertyAsync(string id)
{
return _collection.Find(p => p.Id == id).SingleOrDefaultAsync();
Expand Down Expand Up @@ -512,13 +512,13 @@ public async Task<bool> DeletePropertyAsync(string id)
}
```

```cs {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
```c# {file="src/Monget.Domain/Interfaces/IPropertyService.cs"}
Task<Property> GetPropertyAsync(string id);
Task<Property> UpdatePropertyAsync(string id, Property property);
Task<bool> DeletePropertyAsync(string id);
```

```cs {file="src/Monget.API/Controllers/PropertiesController.cs"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs"}
[HttpGet("{id}")]
public async Task<ActionResult<PropertyResponse>> GetByIdAsync(string id)
{
Expand Down
21 changes: 10 additions & 11 deletions content/guides/dotnet-core-mongo/03-controller-unit-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
title: Controller Unit Testing
author: Nikko Miu
toc: true
draft: true
weight: 3
tags:
- dotnet
Expand All @@ -23,7 +22,7 @@ I'm going to be using the
[.NET Core Testing Best Practices](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices)
as a guideline for how I write tests. One part of this includes a naming convention of test method names:

```cs
```c#
public void MethodToTest_Condition_Expectation()
```

Expand Down Expand Up @@ -52,7 +51,7 @@ dotnet add ./tests/Monget.Tests.Unit/Monget.Tests.Unit.csproj reference ./src/Mo

## Create MappingProfile Test

```cs {file="tests/Monget.Tests.Unit/API/MappingProfileTests.cs"}
```c# {file="tests/Monget.Tests.Unit/API/MappingProfileTests.cs"}
namespace Monget.Tests.Unit.API;

using AutoMapper;
Expand Down Expand Up @@ -120,7 +119,7 @@ since they don't exist on our API model.

Let's go update our mapping profile to explicitly set these properties when mapping between these two types:

```cs {file="src/Monget.API/MappingProfile.cs",add_lines="3-6",rem_lines="7"}
```c# {file="src/Monget.API/MappingProfile.cs",add_lines="3-6",rem_lines="7"}
public MappingProfile()
{
CreateMap<PropertyRequest, Property>()
Expand Down Expand Up @@ -154,7 +153,7 @@ is helping us make these tests truly _unit_ tests.

I'm going to break down the testing of our controller methods. First let's test the `ListAsync()` method:

```cs {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
```c# {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
namespace Monget.Tests.Unit.API.Controllers;

using AutoFixture;
Expand Down Expand Up @@ -248,7 +247,7 @@ public class PropertiesControllerTests

With these in place we can move on to the `CreateAsync()` method:

```cs {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
```c# {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
[Fact]
public async void Create_ReturnsNewProperty()
{
Expand Down Expand Up @@ -290,7 +289,7 @@ the database. The second is when the entity does not exist in the database. Righ
actually exists in the database before returning so we need to update our controller to support returning `NotFound()`
when the record coming back from the service is null.

```cs {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
```c# {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
[Fact]
public async void GetById_Existing_ReturnProperty()
{
Expand Down Expand Up @@ -331,7 +330,7 @@ public async void GetById_NotExisting_ReturnNotFound()
With this in place, let's update the controller to support the `NotFound()` result when the object doesn't exist in our
database:

```cs {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="5-8"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="5-8"}
[HttpGet("{id}")]
public async Task<ActionResult<PropertyResponse>> GetByIdAsync(string id)
{
Expand All @@ -347,7 +346,7 @@ public async Task<ActionResult<PropertyResponse>> GetByIdAsync(string id)

### Update Method

```cs {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
```c# {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
[Fact]
public async void Update_Existing_ReturnUpdatedProperty()
{
Expand Down Expand Up @@ -394,7 +393,7 @@ public async void Update_NotExisting_ReturnNotFound()
}
```

```cs {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="7-10"}
```c# {file="src/Monget.API/Controllers/PropertiesController.cs",add_lines="7-10"}
[HttpPut("{id}")]
public async Task<ActionResult<PropertyResponse>> UpdateAsync(string id, [FromBody] PropertyRequest property)
{
Expand All @@ -412,7 +411,7 @@ public async Task<ActionResult<PropertyResponse>> UpdateAsync(string id, [FromBo

### Delete Method

```cs {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
```c# {file="tests/Monget.Tests.Unit/API/Controllers/PropertiesControllerTests.cs"}
[Theory]
[InlineData(typeof(OkResult), true)]
[InlineData(typeof(NoContentResult), false)]
Expand Down
10 changes: 7 additions & 3 deletions content/guides/dotnet-core-mongo/04-add-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ tags:
- mongodb
---

<!--more-->

## DbContext Class

Before we start, let's create a `DbContext` class that will contain our various collections and maintin our database
connection. This will help reduce the amout of duplicate code in our services as well as centralizing the creation of a
`MongoClient`.

```cs {file="src/Monget.Domain/DbContext.cs"}
```c# {file="src/Monget.Domain/DbContext.cs"}
namespace Monget.Domain;

using Monget.Domain.Models;
Expand All @@ -36,13 +40,13 @@ public class DbContext

Update our `Program.cs` to create a singleton of our `DbContext`:

```cs {file="src/Monget.API/Program.cs"}
```c# {file="src/Monget.API/Program.cs"}
builder.Services.AddSingleton<DbContext>();
```

Update the `PropertyService.cs` to use our new `DbContext` object:

```cs {file="src/Monget.Domain/Services/PropertyService.cs"}
```c# {file="src/Monget.Domain/Services/PropertyService.cs"}
namespace Monget.Domain.Services;

using Monget.Domain.Interfaces;
Expand Down
16 changes: 12 additions & 4 deletions content/guides/golang-graphql-ent/09-misc-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,8 @@ we don't have access to any of the private constants, variables, funcs, or struc
that we are testing. I am an advocate of testing our public API via the `_test` package. This is because we are limited
to what any consumer of our package has to work with, and we can't test things that can't be reached by the public API.

### Refactoring Construction

We happen to have a couple of issues within our `cmd` package right now. The first one is that we can't easily pass the
arguments, `stdout`, or `stderr` into our cmd. The second issue is that our `rootCmd`, `apiCmd`, `migrateCmd`, and
`seedCmd` are all defined as global variables within our package. This will cause issues with testing our API command
Expand Down Expand Up @@ -794,10 +796,14 @@ func newRootCmd() *cobra.Command {
}
```

With this in place, our app should be working again. However, we still have some issues with our testing. First, if you
look at the `executeWithArgs()` func in `cmd_test.go`, you'll notice that we can't use the `SetArgs()`, `SetOut()`, nor
`SetErr()` methods on the `rootCmd` since we don't have a `rootCmd` anymore on the global scope. So, let's add an
`Option` type in a new `cmd/opt.go` file with the options we need:
With this in place, our app should be working again. However, we still have some issues with our testing that we need to
resolve.

### Adding Options

First, if you look at the `executeWithArgs()` func in `cmd_test.go`, you'll notice that we can't use the `SetArgs()`,
`SetOut()`, nor `SetErr()` methods on the `rootCmd` since we don't have a `rootCmd` anymore on the global scope. So,
let's add an `Option` type in a new `cmd/opt.go` file with the options we need:

```go {file="cmd/option.go"}
package cmd
Expand Down Expand Up @@ -889,6 +895,8 @@ Notice how we are adding the `With` options to our `Execute()` func without **ne
this makes for a cleaner interface into overriding the default values for this without mandating these be passed into
our func.

### Retest

Let's now test our API command with a new `cmd/api_test.go`:

```go {file="cmd/api_test.go"}
Expand Down

0 comments on commit dc302f5

Please sign in to comment.