-
-
Save Elfocrash/101ffc29947832545cdaebcb259c2f44 to your computer and use it in GitHub Desktop.
using System.Net.Http; | |
using System.Net.Http.Headers; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Mvc.Testing; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.DependencyInjection.Extensions; | |
using Tweetbook.Contracts.V1; | |
using Tweetbook.Contracts.V1.Requests; | |
using Tweetbook.Contracts.V1.Responses; | |
using Tweetbook.Data; | |
namespace Tweetbook.IntegrationTests | |
{ | |
public class IntegrationTest | |
{ | |
protected readonly HttpClient TestClient; | |
protected IntegrationTest() | |
{ | |
var appFactory = new WebApplicationFactory<Startup>() | |
.WithWebHostBuilder(builder => | |
{ | |
builder.ConfigureServices(services => | |
{ | |
services.RemoveAll(typeof(DataContext)); | |
services.AddDbContext<DataContext>(options => { options.UseInMemoryDatabase("TestDb"); }); | |
}); | |
}); | |
TestClient = appFactory.CreateClient(); | |
} | |
protected async Task AuthenticateAsync() | |
{ | |
TestClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", await GetJwtAsync()); | |
} | |
protected async Task<PostResponse> CreatePostAsync(CreatePostRequest request) | |
{ | |
var response = await TestClient.PostAsJsonAsync(ApiRoutes.Posts.Create, request); | |
return await response.Content.ReadAsAsync<PostResponse>(); | |
} | |
private async Task<string> GetJwtAsync() | |
{ | |
var response = await TestClient.PostAsJsonAsync(ApiRoutes.Identity.Register, new UserRegistrationRequest | |
{ | |
Email = "[email protected]", | |
Password = "SomePass1234!" | |
}); | |
var registrationResponse = await response.Content.ReadAsAsync<AuthSuccessResponse>(); | |
return registrationResponse.Token; | |
} | |
} | |
} |
using System.Collections.Generic; | |
using System.Net; | |
using System.Net.Http; | |
using System.Threading.Tasks; | |
using FluentAssertions; | |
using Tweetbook.Contracts.V1; | |
using Tweetbook.Contracts.V1.Requests; | |
using Tweetbook.Domain; | |
using Xunit; | |
namespace Tweetbook.IntegrationTests | |
{ | |
public class PostsControllerTests : IntegrationTest | |
{ | |
[Fact] | |
public async Task GetAll_WithoutAnyPosts_ReturnsEmptyResponse() | |
{ | |
// Arrange | |
await AuthenticateAsync(); | |
// Act | |
var response = await TestClient.GetAsync(ApiRoutes.Posts.GetAll); | |
// Assert | |
response.StatusCode.Should().Be(HttpStatusCode.OK); | |
(await response.Content.ReadAsAsync<List<Post>>()).Should().BeEmpty(); | |
} | |
[Fact] | |
public async Task Get_ReturnsPost_WhenPostExistsInTheDatabase() | |
{ | |
// Arrange | |
await AuthenticateAsync(); | |
var createdPost = await CreatePostAsync(new CreatePostRequest {Name = "Test post"}); | |
// Act | |
var response = await TestClient.GetAsync(ApiRoutes.Posts.Get.Replace("{postId}", createdPost.Id.ToString())); | |
// Assert | |
response.StatusCode.Should().Be(HttpStatusCode.OK); | |
var returnedPost = await response.Content.ReadAsAsync<Post>(); | |
returnedPost.Id.Should().Be(createdPost.Id); | |
returnedPost.Name.Should().Be("Test post"); | |
} | |
} | |
} |
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<TargetFramework>netcoreapp2.2</TargetFramework> | |
<IsPackable>false</IsPackable> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="FluentAssertions" Version="5.7.0" /> | |
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" /> | |
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.2.0" /> | |
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | |
<PackageReference Include="xunit" Version="2.4.0" /> | |
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> | |
</ItemGroup> | |
<ItemGroup> | |
<ProjectReference Include="..\Tweetbook\Tweetbook.csproj" /> | |
</ItemGroup> | |
</Project> |
Hey 👋. The ApiRoutes is a class I created in the main project to manage the application’s uris in an elegant way. It’s manually created and it can be found in the project’s main repo under Contracts.
Just Perfect! I am going to 'steal' this technique. Thanks, Nick!
Awesome!!!!
What great way to make integrations test!!!! Really appreciate that!
Hi, Thanks for your work.
I would like to note that "services.RemoveAll(typeof(DataContext));" didn't work for me because The test used the actual DB context not the InMemory DB.
I replaced it with
var descriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<ApplicationDbContext>));
if (descriptor != null)
{
services.Remove(descriptor);
}
Like Ms docs
Hi, Thanks for your work.
I would like to note that "services.RemoveAll(typeof(DataContext));" didn't work for me because The test used the actual DB context not the InMemory DB.
I replaced it withvar descriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>)); if (descriptor != null) { services.Remove(descriptor); }
Like Ms docs
Had the same issue. Works for me now with your replacement.
Can you please give the path seeing ApiRoutes.cs class. I can not find it anywhere.
Can you please give the path seeing ApiRoutes.cs class. I can not find it anywhere.
@sravanithamatamqualbrain
I don't know if Nick will be mad at me because he might want you to subscribe in order to get source code or smth. Idea is simple. You need to maneuver with static keyword and nested classes. Example(assuming that controller name is: UsersController):
public static class ApiRoutes
{
private static readonly string _baseUrl = "https://localhost:blabla/api/";
public static class Users
{
private static readonly string _usersControllerUrl = string.Concat(_baseUrl, "users");
public static readonly string GetAll = _usersControllerUrl;
public static readonly string Get = string.Concat(_usersControllerUrl, "/{userId}");
public static readonly string Delete = string.Concat(_usersControllerUrl, "/{userId}");
}
}
Thanks for posting this @trolit, I should have proivided this myself but I had the notifications suppressed.
@trolit exactly what I came here for, thanks 👍
Hey 👋. The ApiRoutes is a class I created in the main project to manage the application’s uris in an elegant way. It’s manually created and it can be found in the project’s main repo under Contracts.
Where do we find the main project?
I am trying to integration test my .NET 5 project using similar setup to what has been described in the video. The unit test run fine when I run them individually but when I run them all at once first to be executed passes and rest fail, when I debugged it was because the user already existed. I think the context is being shared among the tests but I do not know how to not share it. Any help please?
Ok I figured it out. I had to give different database name for each run
the code is as below
var dbName = Guid.NewGuid().ToString(); var appFactory = new WebApplicationFactory<Startup>() .WithWebHostBuilder(builder => { builder.ConfigureServices(services => { var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<DataContext>)); if (descriptor != null) { services.Remove(descriptor); } services.AddDbContext<DataContext>(options => { options.UseInMemoryDatabase(dbName); }); }); }); TestClient = appFactory.CreateClient();
i got a null reference error on variable response in GetJwtAsync() method. I copied the same code. I use .net core 5.0 web api. Anyone know the fix?
`private async Task GetJwtAsync()
{
var response = await TestClient.PostAsJsonAsync(ApiRoutes.Identity.Register, new UserRegistrationRequest
{
Email = "[email protected]",
Password = "SomePass1234!"
});
var registrationResponse = await response.Content.ReadAsAsync<AuthSuccessResponse>();
return registrationResponse.Token;
}`
Hey 👋. The ApiRoutes is a class I created in the main project to manage the application’s uris in an elegant way. It’s manually created and it can be found in the project’s main repo under Contracts.
Where do we find the main project?
I have found this repo where credits were also given to Nick: https://github.com/MohamedAshraf004/TweetbookAPI
Hey wave. The ApiRoutes is a class I created in the main project to manage the application’s uris in an elegant way. It’s manually created and it can be found in the project’s main repo under Contracts.
Where do we find the main project?
I have found this repo where credits were also given to Nick: https://github.com/MohamedAshraf004/TweetbookAPI
This repo is no longer available
Hi Nick, I noticed when you use the HTTP Client you do not pass a URI into the
GetAsync()
method.For test:
ApiRoutes.Posts.GetAll
as an argument.ApiRoutes.Posts.Get.Replace("{postId}", createdPost.Id.ToString())
as argument.Rather than manually creating the URI String, the technique you use is much more elegant.
Can you help me out with a bit more info? where does
ApiRoutes.Posts.*
comes from and how I can do something similar?