0% found this document useful (0 votes)
77 views

Functional Testing For .NET Core API

The document discusses functional testing for ASP.NET Core APIs. It explains that functional testing determines if a piece of software acts as intended without knowledge of internal logic. For API testing, requests expected to pass and fail are prepared. An example API with authentication is provided, and sample tests are written using NUnit to test different request scenarios and assert expected responses.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
77 views

Functional Testing For .NET Core API

The document discusses functional testing for ASP.NET Core APIs. It explains that functional testing determines if a piece of software acts as intended without knowledge of internal logic. For API testing, requests expected to pass and fail are prepared. An example API with authentication is provided, and sample tests are written using NUnit to test different request scenarios and assert expected responses.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

22/12/21 22:40 Functional testing for ASP.

NET Core API | by Andrew Kulta | Medium

Get started Open in app

Andrew Kulta
200 Followers About Follow

You have 2 free member-only stories left this month. Sign up for Medium and get an extra one

Functional testing for ASP.NET Core API


Andrew Kulta Oct 16 · 2 min read

Functional testing is next level above the unit tests and gives us confidence that code
which we wrote works as it intended to. If we talking about functional testing in scope
of asp.net we mean a way how we test our API.

What actually functional testing is?

Functional testing is the process through which we determine if a piece of software


is acting in accordance with pre-determined requirements. It uses black-box testing
techniques, in which the tester has no knowledge of the internal system logic.

In scope of API we need to prepare possible requests which we expect to get and be
sure that

Should we even spend time for it?


Definitely! If you don`t write integrational tests than functional testing is a solution to
be confident that you code has a bit fewer bugs that it could have. When you have
ability to write integrational tests than for your it should be simple to reuse common
code base for functional and for integrational tests. One difference will be in proper
environmental setup.

Let define simple API


https://medium.com/@kylia669/functional-testing-for-asp-net-core-api-4318df89311a 1/6
22/12/21 22:40 Functional testing for ASP.NET Core API | by Andrew Kulta | Medium

In test purposes out controller contains only single action to create some entity. it
Get started Open in app
could be any entity which required by our business rules. Besides we should
remember about authentication nowadays all APIs are protected by some kind of
authentication. Let`s assume that current API requires Authorization header with
Bearer token.

1 [ApiController]
2 public class MyController : ControllerBase
3 {
4 private readonly IService _service;
5
6 public MyController(IService service)
7 {
8 _service = service;
9 }
10
11 [HttpPost("entities")]
12 [ProducesResponseType(typeof(CreateResponse), (int)HttpStatusCode.OK)]
13 [ProducesResponseType(typeof(ExceptionResponse), (int)HttpStatusCode.BadRequest)]
14 public Task<CreateResponse> CreateAsync([FromBody] CreateRequest request)
15 {
16 return _service.CreateAsync(request);
17 }
18 }

ApiController.cs
hosted with ❤ by GitHub view raw

How will functional test look like for this controller ?


In my test project I used NUnit as test framework but it s up to you to choose which
one better suites for you needs. NUnit has all required functionality to write good
tests also it`s quite popular on the market.

Nuget packages which should be included in test project are:

dotnet add package NUnit

dotnet add package NUnit3TestAdapter

1 [TestFixture]
2 public class ApiControllerTests
3 {
4 private const string CreateUrl = "/entities";
5
https://medium.com/@kylia669/functional-testing-for-asp-net-core-api-4318df89311a 2/6
22/12/21 22:40 Functional testing for ASP.NET Core API | by Andrew Kulta | Medium

6 private readonly TokenBuilder _tokenBuilder = new();


Get
7 started Open in app
8 private TestServer? _server;
9 private HttpClient? _client;
10
11 [SetUp]
12 public void Setup()
13 {
14
15 var settings = new Settings
16 {
17 SymmetricFuncTestKey = "your key for functional tests"
18 };
19
20 var builder = new WebHostBuilder()
21 .UseStartup<Startup>()
22 .ConfigureTestServices(services =>
23 {
24 // Mock your external services here
25 })
26 .ConfigureServices(services =>
27 {
28 // Change authentication to use bearer token which signed by symmetric ke
29 services.PostConfigure<JwtBearerOptions>(JwtBearerDefaults.Authentication
30 {
31 options.TokenValidationParameters = new TokenValidationParameters
32 {
33 IssuerSigningKey =
34 new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.Symm
35 ValidateIssuerSigningKey = true,
36 ValidateIssuer = true,
37 ValidateAudience = true,
38 ValidateLifetime = true,
39 ValidIssuer = TestConstants.Issuer,
40 ValidAudience = TestConstants.Audience,
41 };
42 });
43 });
44 _server = new TestServer(builder);
45 _client = _server.CreateClient();
46 }
47
48 [Test]
49 public async Task CreateAsync_Should_ReturnNotAuthenticated_When_RequestWithoutAuthTo
50 {
51 // Arrange
52 var request = new CreateRequest
53 {
https://medium.com/@kylia669/functional-testing-for-asp-net-core-api-4318df89311a 3/6
22/12/21 22:40 Functional testing for ASP.NET Core API | by Andrew Kulta | Medium

54 PropertyName = "propertyValue"
Get
55
started };Open in app
56 var json = JsonConvert.SerializeObject(request);
57 using var data = new StringContent(json, Encoding.UTF8, "application/json");
58
59 // Act
60 var response = await _client?.PostAsync(CreateUrl, data)!;
61
62 // Assert
63 response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
64 }
65
66 [Test]
67 public async Task CreateAsync_Should_Return400_When_RequestValidationFailed()
68 {
69 // Arrange
70 var request = new CreateRequest();
71 var json = JsonConvert.SerializeObject(request);
72 using var data = new StringContent(json, Encoding.UTF8, "application/json");
73 var token = await _tokenBuilder.BuildJWTToken();
74 _client?.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
75
76 // Act
77 var response = await _client?.PostAsync(CreateUrl, data)!;
78
79 // Assert
80 response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
81 }
82
83 [Test]
84 public async Task CreateAsync_Should_ReturnCreateResponse()
85 {
86 // Arrange
87 var request = new CreateRequest
88 {
89 PropertyName = "propertyValue"
90 };
91 var json = JsonConvert.SerializeObject(request);
92 using var data = new StringContent(json, Encoding.UTF8, "application/json");
93 var token = await _tokenBuilder.BuildJWTToken();
94 _client?.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
95
96 var expected = new CreateResponse
97 {
98 PropertyName = "propertyValue"
99 };
100
101 // Act
https://medium.com/@kylia669/functional-testing-for-asp-net-core-api-4318df89311a 4/6
22/12/21 22:40 Functional testing for ASP.NET Core API | by Andrew Kulta | Medium
101 // Act
102 var response = await _client?.PostAsync(CreateUrl, data)!;
Get started Open in app
103
104 // Assert
105 response.StatusCode.Should().Be(HttpStatusCode.OK);
106 var responseBody = await response.Content.ReadAsStringAsync();
107 var responseObject = JsonConvert.DeserializeObject<CreateResponse>(responseBody);
108 responseObject.Should().BeEquivalentTo(expected);
109 }
110 }

We should cover that API endpoint protected by authentication and clients can`t
request it without proper token. In order to do this we need to prepare test server
with proper authentication setup. To do it in setup we need to override
JwtBearerOptions with our test authentication which relies on auth token signed by
SymmetricSecurityKey. To be compliant with security rules we should avoid to store
any secrets in code and I don`t suggest you to violate this rule even for test project.

When configuration for authentication is ready, in testcases proper token should be


generated to proceed to business logic execution. We can separate token generation
into TokenBuilder and use it when we need to get auth token.

1 public static class TestConstants


2 {
3 public static string Audience { get; set; } = "Audience";
4
5 public static string Issuer { get; set; } = "Issuer";
6 }
7
8 public class TokenBuilder
9 {
10 public string BuildJWTToken()
11 {
12 var settings = new Settings
13 {
14 SymmetricFuncTestKey = "your key for functional tests"
15 };
16 var privateKey = settings.SymmetricFuncTestKey;
17 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(privateKey));
18 var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
19 var jwtValidity = DateTime.UtcNow.AddMinutes(5);
20
21 var token = new JwtSecurityToken(
22 TestConstants.Issuer,
https://medium.com/@kylia669/functional-testing-for-asp-net-core-api-4318df89311a 5/6
22/12/21 22:40 Functional testing for ASP.NET Core API | by Andrew Kulta | Medium

23 TestConstants.Audience,
Get started
24 Open in appjwtValidity,
expires:
25 signingCredentials: creds,
26 claims: new List<Claim>
27 {
28 new (ClaimTypes.Role, "owner"),
29 });
30
31 return new JwtSecurityTokenHandler().WriteToken(token);
32 }
33 }

TokenBuilder.cs
hosted with ❤ by GitHub view raw

In conclusion I hope you get feeling that functional tests are quite simple and it allows
to verify you API each time when something changed. Functional tests could be
included as a step in your build pipeline. It gives to even to confidence that
everything works good before deploying to production.

Aspnetcore C Sharp Programming Functional Testing Test Automation Api Testing

About Write Help Legal

Get the Medium app

https://medium.com/@kylia669/functional-testing-for-asp-net-core-api-4318df89311a 6/6

You might also like