Skip to content

Commit db64a96

Browse files
author
Ajay kumar
committed
[Blog] [Ajay]: Add blog for integration with database
1 parent 6367396 commit db64a96

File tree

8 files changed

+147
-2
lines changed

8 files changed

+147
-2
lines changed

TestArena/Blog/BlogHome.razor

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,10 @@
2626
Date="@DateTime.Today.Date.ToLongDateString()" Category="Integration testing"
2727
BlogUrl="/blog/integration-testing-in-dotnet-intro" />
2828
</div>
29+
<div class="col">
30+
<Thumbnail ImageUrl="images/blog/integration-testing/handling-database/banner.png"
31+
Title="Integration testing for dotnet core APIs: Handling database" Author="Ajay kumar"
32+
Date="@DateTime.Today.Date.ToLongDateString()" Category="Integration testing"
33+
BlogUrl="/blog/integration-testing-in-dotnet-with-database" />
34+
</div>
2935
</div>

TestArena/Blog/IntegrationTesting/Intro/Index.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,6 @@ public async Task Get_ById_SuperHero_Returns_SuperHero()
206206
<p>Such scenarios highlight the importance of integration tests in catching unintended changes or bugs in the application behavior.</p>
207207
</Section>
208208
<p>This is it for the basic setup demo. I will be covering more in the future articles like, how to work with database, authentication, events etc.</p>
209-
<EndNotes RepositoryLink="https://github.com/ajaysskumar/pact-net-example" />
209+
<EndNotes RepositoryLink="https://github.com/ajaysskumar/SuperHeroSolution" />
210210

211211
</BlogContainer>
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
@page "/blog/integration-testing-in-dotnet-with-database"
2+
@using TestArena.Blog.Common
3+
4+
5+
<BlogContainer>
6+
<Header Title="Integration testing for dotnet core APIs: Handling database"
7+
Image="/images/blog/integration-testing/handling-database/banner.png" PublishedOn="@DateTime.Now" Authors="Ajay Kumar">
8+
</Header>
9+
10+
<Section Heading="What are integration tests in context of APIs?" Level="4">
11+
<p>In the context of <b>.NET Core APIs</b> for a blog, integration tests are automated tests that evaluate the
12+
functionality of various parts of your application working together as a whole. Specifically, these tests
13+
ensure that multiple components — such as controllers, database access, middleware, internal and external
14+
services — function correctly when integrated, as opposed to functioning correctly only in isolation (which
15+
would be covered by unit tests).</p>
16+
<p>Here is a quick one-liner summary on popular kinds of testing for an API codebase:</p>
17+
<ul>
18+
<li><b>Unit Tests:</b> Validate individual components like controllers or services in isolation.</li>
19+
<li><b>Integration Tests:</b> Verify the interaction between multiple components (e.g., API, database,
20+
middleware) as a cohesive system.</li>
21+
<li><b>Contract Tests:</b> Ensure that API endpoints conform to agreed-upon interfaces or expectations
22+
between services.</li>
23+
</ul>
24+
<p>Integration tests will help you in identifying possible bugs introduced due to any new changes in your code.
25+
</p>
26+
27+
<BlogImage ImagePath="/images/blog/integration-testing/intro/Build process when integration tests fail.webp"
28+
Description="Build process when integration tests fail" Number="1" />
29+
30+
<CodeSnippet Description="APIs for SuperHero" Number="1">
31+
[ApiController]
32+
[Route("[controller]")]
33+
public class SuperHeroController(ISuperHeroRepository superHeroRepository)
34+
: ControllerBase
35+
{
36+
[HttpGet("")]
37+
public async Task&lt;IEnumerable&lt;SuperHero&gt;&gt; Get()
38+
{
39+
return await superHeroRepository.GetAllSuperHeroes();
40+
}
41+
42+
[HttpGet("{id}")]
43+
public async Task&lt;IActionResult&gt; GetById(int id)
44+
{
45+
var superHero = await superHeroRepository.GetSuperHeroById(id);
46+
if (superHero == null)
47+
{
48+
return NotFound();
49+
}
50+
51+
return Ok(superHero);
52+
}
53+
}
54+
</CodeSnippet>
55+
</Section
56+
57+
<Section Heading="Summary" Level="4">
58+
<p>Welcome to the 2nd post in our Integration testing series. You may check out the previous post that introduces the concept of writing integration tests using <b>WebApplicationFactory</b> in dotnet below:</p>
59+
<BlogReferenceCard
60+
Title="Integration testing for dotnet core APIs: Introduction"
61+
Description="Integration testing for dotnet core APIs: Introduction"
62+
Url="/blog/integration-testing-in-dotnet-intro"
63+
ImageUrl="/images/blog/integration-testing/intro/banner.png"
64+
Source="devcodex.in"/>
65+
66+
<p>Almost every application relies on persistent storage, typically through a database. Integration testing with a real database can be challenging, especially when trying to maintain isolation and consistency across tests. In this post, we will explore how to effectively manage database dependencies in integration tests using <b>WebApplicationFactory</b> and containerized databases.</p>
67+
<p><b>Pre-requisites</b>, in case you want to follow the same setup on your system:</p>
68+
<ul>
69+
<li><b>Postgres DB Server:</b> This is needed in case you want to test out the main application.</li>
70+
<li><b>Docker:</b> This is needed to run test containers.</li>
71+
</ul>
72+
</Section>
73+
74+
<Section Heading="Setting Up the Database" Level="4">
75+
<p>To do this we need to first introduce a database in our sample superhero API. For this demo purpose, we have used a Postgres database.</p>
76+
<p>For this, we made the below changes in our superhero API:</p>
77+
<CodeSnippet Description="Connection String in appsettings.json" Number="2">
78+
{
79+
"ConnectionStrings": {
80+
"WebApiDatabase": "Host=localhost; Database=superhero; Username=postgres; Password=postgres"
81+
}
82+
}
83+
</CodeSnippet>
84+
<p>Install the package <b>Npgsql.EntityFrameworkCore.PostgreSQL</b> in the main API project. After that, we need to provide options in the program file to guide the application to use the Postgres database:</p>
85+
<CodeSnippet Description="Configuring DbContext in Program.cs" Number="3">
86+
builder.Services.AddDbContext&lt;SuperHeroDbContext&gt;(opt =>
87+
opt.UseNpgsql(configuration.GetConnectionString("WebApiDatabase")));
88+
</CodeSnippet>
89+
<p>Along with this, we also need to create a migration, if not already present, to set up the database schema.</p>
90+
</Section>
91+
92+
<Section Heading="Unit Test Example" Level="4">
93+
<p>Finally, our unit test:</p>
94+
<CodeSnippet Description="Unit Test for Get All SuperHeroes API" Number="4">
95+
[Fact(DisplayName = "Get all superheros API returns all superheroes")]
96+
public async Task Get_All_SuperHeroes_Returns_List_Of_SuperHero()
97+
{
98+
// Arrange
99+
factory.SharedFixture.SuperHeroDbContext.SuperHero.AddRange(new List&lt;SuperHero&gt;()
100+
{
101+
new SuperHero(1, "Batman","Bruce Wayne","Short distance fly,Common sense","Gotham", 40),
102+
new SuperHero(2, "Superman", "Clark kent", "Fly, Shoot laser beam, Super strength, ice breath","Gotham", 42),
103+
new SuperHero(3, "Robin", "John Blake", "Detective","Gotham", 35)
104+
});
105+
await factory.SharedFixture.SuperHeroDbContext.SaveChangesAsync();
106+
107+
// Act
108+
var response = await factory.CreateClient().GetAsync("/SuperHero");
109+
110+
// Assert
111+
response.StatusCode.Should().Be(HttpStatusCode.OK);
112+
var superHeroes = await response.Content.ReadFromJsonAsync&lt;List&lt;SuperHero&gt;&gt;();
113+
superHeroes.Should().NotBeEmpty();
114+
superHeroes![0].Id.Should().Be(1);
115+
superHeroes![0].SuperName.Should().Be("Batman");
116+
}
117+
</CodeSnippet>
118+
<p>Let's understand the above test:</p>
119+
<ul>
120+
<li>Now before any of the tests will start executing, our <b>SharedFixture</b> code will run and it will fire up the test container as you can see in the below image:</li>
121+
</ul>
122+
<BlogImage ImagePath="/images/blog/integration-testing/handling-database/Test containers in action.webp"
123+
Description="Test containers in action" Number="2" />
124+
<ul>
125+
<li>In the <b>Arrange</b> step, I added a few records directly to the database using the <b>SharedFixture</b>.</li>
126+
<li>After the above step, there are some records in the system and in the <b>Act</b> step, we will be trying to call the GET superheroes API.</li>
127+
<li>If everything is correct, we should be able to see our tests being passed like below:</li>
128+
</ul>
129+
<BlogImage ImagePath="/images/blog/integration-testing/handling-database/Tests passing.webp"
130+
Description="Tests passing" Number="3" />
131+
</Section>
132+
<p>This is it for the setup with database. I will be covering more in the future articles like, how to work with authentication, events etc.</p>
133+
<EndNotes RepositoryLink="https://github.com/ajaysskumar/SuperHeroSolution" />
134+
</BlogContainer>

TestArena/Blog/PactNet/handling-events/Index.razor

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010
<p>This is a continuation of the PACT for .NET series where I am going to cover the usage of PACT in event-based systems.</p>
1111
<p>This article assumes the readers will have a basic understanding of event-based systems and frameworks. In case not, a good place to start can be <a href="https://www.rabbitmq.com/tutorials">RabbitMQ Tutorials</a>.</p>
1212
<p>I will be using the same repo setup that I have used to demonstrate usage in API-based systems. I have covered the setup in detail in a previous blog in this series:</p>
13-
<p><a href="/blog/contract-testing-pact-net-intro">Contract testing for APIs: Intro to PACT for .NET Core</a></p>
13+
<BlogReferenceCard
14+
Title="Contract testing for APIs: Intro to PACT for .NET Core"
15+
Description="Intro to PACT for .NET Core: API contract testing"
16+
Url="/blog/contract-testing-pact-net-intro"
17+
ImageUrl="/images/blog/pact/intro/header_landscape.png"
18+
Source="devcodex.in"/>
1419
</Section>
1520

1621
<Section Heading="Scenario: Event Flow" Level="5">
28.3 KB
Loading
29 KB
Loading
2.83 MB
Loading
121 KB
Loading

0 commit comments

Comments
 (0)