Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,11 @@ public interface IRepository<T> where T: BaseEntity
Task<IEnumerable<T>> GetAllAsync();

Task<T> GetByIdAsync(Guid id);

Task<T> AddAsync(T entity);

Task<T> UpdateAsync(T entity);

Task DeleteAsync(T entity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,60 @@
using System.Threading.Tasks;
using PromoCodeFactory.Core.Abstractions.Repositories;
using PromoCodeFactory.Core.Domain;

namespace PromoCodeFactory.DataAccess.Repositories
{
public class InMemoryRepository<T>: IRepository<T> where T: BaseEntity
{
protected IEnumerable<T> Data { get; set; }
protected ICollection<T> Data { get; set; }

public InMemoryRepository(IEnumerable<T> data)
public InMemoryRepository(ICollection<T> data)
{
Data = data;
}

public Task<IEnumerable<T>> GetAllAsync()
{
return Task.FromResult(Data);
return Task.FromResult<IEnumerable<T>>(Data);
}

public Task<T> GetByIdAsync(Guid id)
{
return Task.FromResult(Data.FirstOrDefault(x => x.Id == id));
}

/// <inheritdoc />
public Task<T> AddAsync(T entity)
{
Data.Add(entity);
return Task.FromResult(entity);
}

/// <inheritdoc />
public async Task<T> UpdateAsync(T entity)
{
var oldEntity = await GetByIdAsync(entity.Id);
if (oldEntity == null)
throw new Exception($"Entity with id [{entity.Id}] not found");

// stub for in-memory
await DeleteAsync(oldEntity);
await AddAsync(entity);

// save changes

return entity;
}

/// <inheritdoc />
public Task DeleteAsync(T entity)
{
var storedEntity = Data.FirstOrDefault(x => x.Id == entity.Id);
if(storedEntity == null)
throw new Exception($"Entity with id [{entity.Id}] not found");

Data.Remove(storedEntity);
return Task.CompletedTask;
}
}
}
196 changes: 196 additions & 0 deletions Homeworks/Base/src/PromoCodeFactory.WebHost.Tests/EmployeeApiTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
using System.Net;
using System.Net.Http.Json;
using PromoCodeFactory.DataAccess.Data;
using PromoCodeFactory.WebHost.Models;

namespace PromoCodeFactory.WebHost.Tests;

public class EmployeeApiTests(WebHostFixture factory) : IClassFixture<WebHostFixture>
{
private readonly HttpClient _client = factory.CreateClient();

[Fact]
public void FakeData_Contains_Two_Employees()
{
Assert.Equal(2, FakeDataFactory.Employees.Count);
}

[Fact]
public void FakeData_Contains_Two_Roles()
{
Assert.Equal(2, FakeDataFactory.Roles.Count);
}

[Fact]
public async Task EmployeeCreation_Succeed()
{
var employeeRequest = new EmployeeCreationRequest
{
FirstName = "John",
LastName = "Doe",
Email = "[email protected]"
};

var response = await _client.PostAsJsonAsync(factory.ApiRoot + "Employees", employeeRequest);

Assert.Equal(HttpStatusCode.Created, response.StatusCode);

var content = await response.Content.ReadFromJsonAsync<EmployeeResponse>();
Assert.NotNull(content);
Assert.NotEqual(Guid.Empty, content.Id);
Assert.Equal(employeeRequest.Email, content.Email);
Assert.Equal(employeeRequest.FirstName, content.FirstName);
Assert.Equal(employeeRequest.LastName, content.LastName);
}

[Fact]
public async Task Employee_Fails_On_Wrong_Body()
{
var response = await _client.PostAsJsonAsync(factory.ApiRoot + "Employees",
new
{
FullName = "John Doe",
Email = "mymail"
});

Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}

[Fact]
public async Task Employee_Persists_Between_Calls()
{
var employeeRequest = new EmployeeCreationRequest
{
FirstName = "John",
LastName = "Doe",
Email = "[email protected]"
};

var response = await _client.PostAsJsonAsync($"{factory.ApiRoot}Employees", employeeRequest);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
var createdEmployee = await response.Content.ReadFromJsonAsync<EmployeeResponse>();
Assert.NotNull(createdEmployee);
Assert.NotEqual(Guid.Empty, createdEmployee.Id);

response = await _client.GetAsync($"{factory.ApiRoot}Employees/{createdEmployee.Id:D}");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var fetchedEmployee = await response.Content.ReadFromJsonAsync<EmployeeResponse>();
Assert.NotNull(fetchedEmployee);
Assert.Equal(createdEmployee.Id, fetchedEmployee.Id);
Assert.Equal(createdEmployee.Email, fetchedEmployee.Email);
Assert.Equal(createdEmployee.FirstName, fetchedEmployee.FirstName);
Assert.Equal(createdEmployee.LastName, fetchedEmployee.LastName);
Assert.Equivalent(createdEmployee.Roles, fetchedEmployee.Roles);
Assert.Equal(createdEmployee.AppliedPromocodesCount, fetchedEmployee.AppliedPromocodesCount);
}

[Fact]
public async Task Employee_Get_Fails_On_Wrong_Id()
{
var response = await _client.GetAsync($"{factory.ApiRoot}Employees/{Guid.NewGuid():D}");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

private async Task<EmployeeResponse> GetFirstEmployee()
{
var response = await _client.GetAsync($"{factory.ApiRoot}Employees");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var employees = await response.Content.ReadFromJsonAsync<IEnumerable<EmployeeShortResponse>>();
Assert.NotNull(employees);
var employeeShort = employees.FirstOrDefault();
Assert.NotNull(employeeShort);

var employeeResponse = await _client.GetAsync($"{factory.ApiRoot}Employees/{employeeShort.Id:D}");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var employeeFull = await employeeResponse.Content.ReadFromJsonAsync<EmployeeResponse>();
Assert.NotNull(employeeFull);

return employeeFull;
}

[Fact]
public async Task Employee_Get_Without_Id_Returns_Collection()
{
var response = await _client.GetAsync($"{factory.ApiRoot}Employees");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var employees = await response.Content.ReadFromJsonAsync<IEnumerable<EmployeeShortResponse>>();
Assert.NotNull(employees);
Assert.NotEmpty(employees);
}

[Fact]
public async Task Employee_Get_Employee_On_Right_Id()
{
var sourceEmployee = await GetFirstEmployee();

var response = await _client.GetAsync($"{factory.ApiRoot}Employees/{sourceEmployee.Id:D}");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var employee = await response.Content.ReadFromJsonAsync<EmployeeResponse>();
Assert.NotNull(employee);
Assert.Equal(sourceEmployee.Id, employee.Id);
Assert.Equal(sourceEmployee.Email, employee.Email);
Assert.Equal(sourceEmployee.FirstName, employee.FirstName);
Assert.Equal(sourceEmployee.LastName, employee.LastName);
Assert.Equal(sourceEmployee.Roles.Count, employee.Roles.Count);
Assert.Equivalent(sourceEmployee.Roles, employee.Roles);
}

[Fact]
public async Task Employee_Updates_Existing_Employee()
{
var sourceEmployee = await GetFirstEmployee();
Assert.NotNull(sourceEmployee);

sourceEmployee.Email += "+";
sourceEmployee.FirstName += "+";
sourceEmployee.LastName += "+";

var response = await _client.PutAsJsonAsync($"{factory.ApiRoot}Employees/{sourceEmployee.Id:D}", sourceEmployee);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var updatedEmployee = await response.Content.ReadFromJsonAsync<EmployeeResponse>();
Assert.NotNull(updatedEmployee);
Assert.Equal(updatedEmployee.Email, sourceEmployee.Email);
Assert.Equal(updatedEmployee.FirstName, sourceEmployee.FirstName);
Assert.Equal(updatedEmployee.LastName, sourceEmployee.LastName);
}


[Fact]
public async Task Employee_Delete_Existing_Employee_Returns_OK()
{
var sourceEmployee = await GetFirstEmployee();
Assert.NotNull(sourceEmployee);

var response = await _client.DeleteAsync($"{factory.ApiRoot}Employees/{sourceEmployee.Id:D}");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

}

[Fact]
public async Task Employee_Delete_Missing_Employee_Returns_404()
{
var response = await _client.DeleteAsync($"{factory.ApiRoot}Employees/{Guid.NewGuid():D}");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

[Fact]
public async Task Employee_Delete_Existing_Employee_Removes_Employee()
{
var sourceEmployee = await GetFirstEmployee();
Assert.NotNull(sourceEmployee);

var response = await _client.DeleteAsync($"{factory.ApiRoot}Employees/{sourceEmployee.Id:D}");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

response = await _client.GetAsync($"{factory.ApiRoot}Employees/{sourceEmployee.Id:D}");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2"/>
<PackageReference Include="FluentAssertions" Version="8.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0"/>
<PackageReference Include="xunit" Version="2.9.2"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.9" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\PromoCodeFactory.WebHost\PromoCodeFactory.WebHost.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.AspNetCore.Mvc.Testing;

namespace PromoCodeFactory.WebHost.Tests;

public class WebHostFixture() : WebApplicationFactory<Program>
{
public string ApiRoot = "/api/v1/";

}
Loading