Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Giovanni Zuffolini #33

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TestAPI-IntegrationTest/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;
32 changes: 32 additions & 0 deletions TestAPI-IntegrationTest/TestAPI-IntegrationTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>TestAPI_IntegrationTest</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.14" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\TestAPI\TestAPI.csproj" />
</ItemGroup>

</Project>
84 changes: 84 additions & 0 deletions TestAPI-IntegrationTest/WeatherForecastControllerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using TestAPI;

namespace TestAPI_IntegrationTest
{
public class WeatherForecastControllerTest : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _webApplicationFactory;
private IConfiguration _configuration;

public WeatherForecastControllerTest(WebApplicationFactory<Program> webApplicationFactory)
{
_webApplicationFactory = webApplicationFactory;
_configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
}

[Theory]
[InlineData("/WeatherForecast/unauthenticated")]
public async Task Get_EndpointsReturnSuccess(string url)
{
// Arrange
var client = _webApplicationFactory.CreateClient();

// Act
var response = await client.GetAsync(url);

// Assert
Assert.True(response.IsSuccessStatusCode);
}

[Theory]
[InlineData("/WeatherForecast/")]
public async Task Get_EndpointsReturnUnauthenticated(string url)
{
// Arrange
var client = _webApplicationFactory.CreateClient();

// Act
var response = await client.GetAsync(url);

// Assert
Assert.Equal(System.Net.HttpStatusCode.Unauthorized, response.StatusCode);
}

[Theory]
[InlineData("/WeatherForecast/")]
public async Task Get_EndpointsReturnAuthenticated(string url)
{
// Arrange
var client = _webApplicationFactory.CreateClient();

// Act
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, url);
httpRequestMessage.Headers.Add("Authorization", "Bearer " + GetValidToken());
var response = await client.SendAsync(httpRequestMessage);

// Assert
Assert.True(response.IsSuccessStatusCode);
}

private string GetValidToken()
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

var sectoken = new JwtSecurityToken(_configuration["JWT:Issuer"],
_configuration["JWT:Issuer"],
null,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);

var token = new JwtSecurityTokenHandler().WriteToken(sectoken);
return token;
}
}
}
1 change: 1 addition & 0 deletions TestAPI-UnitTest/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;
31 changes: 31 additions & 0 deletions TestAPI-UnitTest/TestAPI-UnitTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>TestAPI_UnitTest</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="Moq" Version="4.20.69" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\TestAPI\TestAPI.csproj" />
</ItemGroup>

</Project>
131 changes: 131 additions & 0 deletions TestAPI-UnitTest/WeatherForecastServiceTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using Moq;
using Newtonsoft.Json;
using System.Globalization;
using TestAPI.Database;
using TestAPI.Models;
using TestAPI.Services;

namespace TestAPI_UnitTest
{
public class WeatherForecastServiceTest
{
private Mock<IWeatherDatabase> GetMockedWeatherDatabase()
{
Dictionary<DateTime, Forecast> forecasts = new Dictionary<DateTime, Forecast>();

var repositoryMock = new Mock<IWeatherDatabase>();
repositoryMock
.Setup(r => r.GetSummariesAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(WeatherDatabaseData.GetDefaultSummaries());
repositoryMock
.Setup(r => r.GetForecastsAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(forecasts);
repositoryMock
.Setup(r => r.AddForecast(It.IsAny<Forecast>())).Callback((Forecast f) => forecasts.Add(f.Id, f));

return repositoryMock;
}

[Theory]
[InlineData(0)]
[InlineData(1)]
public void Get_ForecastDays_ReturnsSameRequestedForecastDaysCount(int forecastDays)
{
// Arrange
var repositoryMock = GetMockedWeatherDatabase();
var weatherForecastService = new WeatherForecastService(repositoryMock.Object);

// Act
var forecast = weatherForecastService.GetAsync(forecastDays, CancellationToken.None);
int actual = forecast.CountAsync().Result;

// Assert
Assert.Equal(forecastDays, actual);
}

[Theory]
[InlineData(1)]
public void Get_SameRequests_ReturnsSameForecastData(int forecastDays)
{
// Arrange
var repositoryMock = GetMockedWeatherDatabase();
var weatherForecastService = new WeatherForecastService(repositoryMock.Object);

// Act
var firstforecast = weatherForecastService.GetAsync(forecastDays, CancellationToken.None).FirstOrDefaultAsync().Result;
var secondforecast = weatherForecastService.GetAsync(forecastDays, CancellationToken.None).FirstOrDefaultAsync().Result;

bool actual = CompareObjects(firstforecast, secondforecast);

// Assert
Assert.True(actual);
}

[Theory]
[InlineData(1, 2)]
public void Get_DifferentRequests_ReturnsDifferentForecastData(int firstRequestForecastDays, int secondRequestForecastDays)
{
// Arrange
var repositoryMock = GetMockedWeatherDatabase();
var weatherForecastService = new WeatherForecastService(repositoryMock.Object);

// Act
var firstforecast = weatherForecastService.GetAsync(firstRequestForecastDays, CancellationToken.None).ToArrayAsync().Result;
var secondforecast = weatherForecastService.GetAsync(secondRequestForecastDays, CancellationToken.None).ToArrayAsync().Result;

bool actual = CompareObjects(firstforecast, secondforecast);

// Assert
Assert.False(actual);
}

[Theory]
[InlineData(-5, "Freezing")]
[InlineData(5, "Cool")]
[InlineData(20, "Warm")]
[InlineData(50, "Hot")]
public void Get_DifferentCelsius_ReturnsRightSummary(int celsius, string resultSummaryId)
{
// Arrange
var repositoryMock = GetMockedWeatherDatabase();
var weatherForecastService = new WeatherForecastService(repositoryMock.Object);
var summaries = new Summary[] {
new Summary
{
Id = "Freezing",
CelsiusLow = null,
CelsiusHigh = 5
}, new Summary
{
Id = "Cool",
CelsiusLow = 5,
CelsiusHigh = 20
}, new Summary
{
Id = "Warm",
CelsiusLow = 20,
CelsiusHigh = 30
}, new Summary
{
Id = "Hot",
CelsiusLow = 30,
CelsiusHigh = null
}};

// Act
var actual = weatherForecastService.GetSummary(summaries, celsius);


// Assert
Assert.True(actual.Id.Equals(resultSummaryId));
}

private bool CompareObjects(object? o1, object? o2)
{
string o1string = JsonConvert.SerializeObject(o1);
string o2string = JsonConvert.SerializeObject(o2);

return o1string.Equals(o2string);
}
}
}
12 changes: 12 additions & 0 deletions TestAPI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Readme.md = Readme.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestAPI-UnitTest", "TestAPI-UnitTest\TestAPI-UnitTest.csproj", "{F706E9B3-C3D3-42DE-9BB8-0EA678450A5A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestAPI-IntegrationTest", "TestAPI-IntegrationTest\TestAPI-IntegrationTest.csproj", "{A3F2BC71-6A0D-4637-A915-28FECF79F116}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -28,6 +32,14 @@ Global
{A720BF0D-868C-404E-9A87-410694A01C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A720BF0D-868C-404E-9A87-410694A01C6F}.Release|Any CPU.Build.0 = Release|Any CPU
{A720BF0D-868C-404E-9A87-410694A01C6F}.Release|Any CPU.Deploy.0 = Release|Any CPU
{F706E9B3-C3D3-42DE-9BB8-0EA678450A5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F706E9B3-C3D3-42DE-9BB8-0EA678450A5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F706E9B3-C3D3-42DE-9BB8-0EA678450A5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F706E9B3-C3D3-42DE-9BB8-0EA678450A5A}.Release|Any CPU.Build.0 = Release|Any CPU
{A3F2BC71-6A0D-4637-A915-28FECF79F116}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A3F2BC71-6A0D-4637-A915-28FECF79F116}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A3F2BC71-6A0D-4637-A915-28FECF79F116}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3F2BC71-6A0D-4637-A915-28FECF79F116}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
19 changes: 12 additions & 7 deletions TestAPI/Database/IWeatherDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
using System.Threading;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using TestAPI.Models;

namespace TestAPI.Database
{
public interface IWeatherDatabase
{
DbSet<Summary> Summaries { get; set; }
DbSet<Forecast> Forecasts { get; set; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
void Migrate();
{
#region Added methods for unit test mocking
Task<IDictionary<DateTime, Forecast>> GetForecastsAsync(DateTime startDate, DateTime endDate, CancellationToken token);
void AddForecast(Forecast forecast);
Task<IEnumerable<Summary>> GetSummariesAsync(CancellationToken token);
#endregion

Task<int> SaveChangesAsync(CancellationToken cancellationToken);
void Migrate();
}
}
Loading