From 6bd3bfc756772d014794e3d9d69d4cd957561b7e Mon Sep 17 00:00:00 2001 From: Sara Gowen <9001998+dynamictulip@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:56:52 +0100 Subject: [PATCH 1/5] Add dedicated types for mocking the `AcademiesDbContext` and `DbSet` These new mocks allow methods using async EF core to be mocked --- .../Mocks/MockAcademiesDbContext.cs | 23 ++++ .../Mocks/MockDbSet.cs | 114 ++++++++++++++++++ .../Usings.cs | 1 + 3 files changed, 138 insertions(+) create mode 100644 tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockAcademiesDbContext.cs create mode 100644 tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbSet.cs diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockAcademiesDbContext.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockAcademiesDbContext.cs new file mode 100644 index 000000000..8a7200d5a --- /dev/null +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockAcademiesDbContext.cs @@ -0,0 +1,23 @@ +using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.Models; + +namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests.Mocks; + +public class MockAcademiesDbContext : Mock +{ + public List SetupMockDbContextGroups(int numMatches) + { + var groups = new List(); + for (var i = 0; i < numMatches; i++) + { + groups.Add(new Group + { + GroupName = $"trust {i}", GroupUid = $"{i}", GroupId = $"TR0{i}", GroupType = "Multi-academy trust" + }); + } + + Setup(academiesDbContext => academiesDbContext.Groups) + .Returns(new MockDbSet(groups).Object); + + return groups; + } +} diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbSet.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbSet.cs new file mode 100644 index 000000000..ef53dfb61 --- /dev/null +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbSet.cs @@ -0,0 +1,114 @@ +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; + +namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests.Mocks; + +/// +/// Use this to create a mock DbSet from a collection of items. The mock DbSet points to the collection so changes to +/// the original collection will be reflected in the mock DbSet and vice versa +/// Adapted from https://jason-ge.medium.com/mock-async-data-repository-in-asp-net-core-3-1-634cb19a3013 +/// +/// +public class MockDbSet : Mock> where TEntity : class +{ + public MockDbSet(IEnumerable items) + { + var itemsAsQueryable = items.AsQueryable(); + + As>() + .Setup(x => x.GetAsyncEnumerator(default)) + .Returns(new TestAsyncEnumerator(itemsAsQueryable.GetEnumerator())); + As>() + .Setup(m => m.Provider) + .Returns(new TestAsyncQueryProvider(itemsAsQueryable.Provider)); + As>() + .Setup(m => m.Expression).Returns(itemsAsQueryable.Expression); + As>() + .Setup(m => m.ElementType).Returns(itemsAsQueryable.ElementType); + As>() + .Setup(m => m.GetEnumerator()).Returns(itemsAsQueryable.GetEnumerator()); + } + + public sealed override Mock As() + { + return base.As(); + } + + private class TestAsyncEnumerator : IAsyncEnumerator + { + private readonly IEnumerator _enumerator; + + public TestAsyncEnumerator(IEnumerator enumerator) + { + _enumerator = enumerator; + } + + public T Current => _enumerator.Current; + + public ValueTask DisposeAsync() + { + return new ValueTask(Task.Run(() => _enumerator.Dispose())); + } + + public ValueTask MoveNextAsync() + { + return new ValueTask(_enumerator.MoveNext()); + } + } + + private class TestAsyncEnumerable : EnumerableQuery, IAsyncEnumerable, IQueryable + { + public TestAsyncEnumerable(Expression expression) + : base(expression) + { + } + + IQueryProvider IQueryable.Provider => new TestAsyncQueryProvider(this); + + public IAsyncEnumerator GetAsyncEnumerator(CancellationToken token) + { + return new TestAsyncEnumerator(this.AsEnumerable().GetEnumerator()); + } + } + + private class TestAsyncQueryProvider : IAsyncQueryProvider + { + private readonly IQueryProvider _innerQueryProvider; + + internal TestAsyncQueryProvider(IQueryProvider innerQueryProvider) + { + _innerQueryProvider = innerQueryProvider; + } + + public IQueryable CreateQuery(Expression expression) + { + return new TestAsyncEnumerable(expression); + } + + public IQueryable CreateQuery(Expression expression) + { + return new TestAsyncEnumerable(expression); + } + + public object? Execute(Expression expression) + { + return _innerQueryProvider.Execute(expression); + } + + public TResult Execute(Expression expression) + { + return _innerQueryProvider.Execute(expression); + } + + public TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken = new()) + { + var expectedResultType = typeof(TResult).GetGenericArguments()[0]; + var executionResult = Execute(expression); + + return (TResult)(typeof(Task).GetMethod(nameof(Task.FromResult))! + .MakeGenericMethod(expectedResultType) + .Invoke(null, new[] { executionResult }) ?? throw new Exception()); + } + } +} diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Usings.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Usings.cs index 37b97ee8d..09afef9b5 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Usings.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Usings.cs @@ -1,3 +1,4 @@ +global using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb; global using Xunit; global using FluentAssertions; global using Moq; From 4bb50cad5096096f720b679e2fd0158c32c3f75e Mon Sep 17 00:00:00 2001 From: Sara Gowen <9001998+dynamictulip@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:10:43 +0100 Subject: [PATCH 2/5] Implement `ITrustProvider` in `Data.AcademiesDb` and remove old academies API TrustProvider --- .../TrustProvider.cs | 36 +++++ .../ITrustProvider.cs | 6 + .../TrustProvider.cs | 66 -------- .../TrustProviderTests.cs | 37 +++++ .../TrustProviderTests.cs | 141 ------------------ 5 files changed, 79 insertions(+), 207 deletions(-) create mode 100644 DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs create mode 100644 DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs delete mode 100644 DfE.FindInformationAcademiesTrusts/TrustProvider.cs create mode 100644 tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs delete mode 100644 tests/DfE.FindInformationAcademiesTrusts.UnitTests/TrustProviderTests.cs diff --git a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs new file mode 100644 index 000000000..5653bed9d --- /dev/null +++ b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs @@ -0,0 +1,36 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore; + +namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb; + +public class TrustProvider : ITrustProvider +{ + private readonly IAcademiesDbContext _academiesDbContext; + + [ExcludeFromCodeCoverage] + public TrustProvider(AcademiesDbContext academiesDbContext) : this((IAcademiesDbContext)academiesDbContext) + { + } + + public TrustProvider(IAcademiesDbContext academiesDbContext) + { + _academiesDbContext = academiesDbContext; + } + + public async Task GetTrustByUkprnAsync(string groupUid) + { + Trust? trust = null; + + var group = await _academiesDbContext.Groups.SingleOrDefaultAsync(g => g.GroupUid == groupUid); + if (group is not null) + { + trust = new Trust( + group.GroupName, + group.Ukprn, + group.GroupType ?? string.Empty + ); + } + + return trust; + } +} diff --git a/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs b/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs new file mode 100644 index 000000000..9a080a120 --- /dev/null +++ b/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs @@ -0,0 +1,6 @@ +namespace DfE.FindInformationAcademiesTrusts.Data; + +public interface ITrustProvider +{ + public Task GetTrustByUkprnAsync(string groupUid); +} diff --git a/DfE.FindInformationAcademiesTrusts/TrustProvider.cs b/DfE.FindInformationAcademiesTrusts/TrustProvider.cs deleted file mode 100644 index c42642abb..000000000 --- a/DfE.FindInformationAcademiesTrusts/TrustProvider.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Net; -using System.Text.Json; -using DfE.FindInformationAcademiesTrusts.AcademiesApiResponseModels; -using DfE.FindInformationAcademiesTrusts.Data; - -namespace DfE.FindInformationAcademiesTrusts; - -public interface ITrustProvider -{ - public Task GetTrustByUkprnAsync(string ukprn); -} - -public class TrustProvider : ITrustProvider -{ - private readonly ILogger _logger; - private readonly HttpClient _httpClient; - - public TrustProvider(IHttpClientFactory httpClientFactory, - ILogger logger) - - { - _logger = logger; - _httpClient = httpClientFactory.CreateClient("AcademiesApi"); - } - - public async Task GetTrustByUkprnAsync(string ukprn) - { - var httpResponseMessage = await _httpClient.GetAsync($"v3/trust/{ukprn}"); - if (httpResponseMessage.IsSuccessStatusCode) - { - await using var contentStream = await httpResponseMessage.Content.ReadAsStreamAsync(); - var json = await JsonSerializer.DeserializeAsync>(contentStream, - new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); - - if (json?.Data?.GiasData?.GroupName == null) throw new JsonException(); - - var trust = new Trust( - json.Data.GiasData.GroupName, - json.Data.GiasData.Ukprn, - json.Data.GiasData.GroupType ?? string.Empty - ); - - return trust; - } - - if (httpResponseMessage.StatusCode == HttpStatusCode.NotFound) - { - return null; - } - - var errorMessage = await httpResponseMessage.Content.ReadAsStringAsync(); - LogHttpError(httpResponseMessage, errorMessage); - throw new HttpRequestException("Problem communicating with Academies API"); - } - - private void LogHttpError(HttpResponseMessage httpResponseMessage, string errorMessage) - { - _logger.LogError( - "Received {statusCode} from Academies API, \r\nendpoint: {endpoint}, \r\ncontent: {errorMessage}, \r\nheaders: {headers}", - httpResponseMessage.StatusCode, - httpResponseMessage.RequestMessage?.RequestUri, - errorMessage, - httpResponseMessage.Headers - ); - } -} diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs new file mode 100644 index 000000000..426871776 --- /dev/null +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs @@ -0,0 +1,37 @@ +using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.Models; +using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests.Mocks; + +namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests; + +public class TrustProviderTests +{ + private readonly TrustProvider _sut; + private readonly List _groups; + + public TrustProviderTests() + { + var mockAcademiesDbContext = new MockAcademiesDbContext(); + _groups = mockAcademiesDbContext.SetupMockDbContextGroups(5); + _sut = new TrustProvider(mockAcademiesDbContext.Object); + } + + [Fact] + public async Task GetTrustsByUkprnAsync_should_return_a_trust_if_group_found() + { + _groups.Add(new Group + { GroupName = "trust 1", GroupUid = "1234", GroupType = "Multi-academy trust", Ukprn = "my ukprn" }); + + var result = await _sut.GetTrustByUkprnAsync("1234"); + + result.Should().BeEquivalentTo(new Trust("trust 1", + "my ukprn", + "Multi-academy trust")); + } + + [Fact] + public async Task GetTrustsByUkprnAsync_should_return_null_when_group_not_found() + { + var result = await _sut.GetTrustByUkprnAsync("987654321"); + result.Should().BeNull(); + } +} diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/TrustProviderTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/TrustProviderTests.cs deleted file mode 100644 index 06830d607..000000000 --- a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/TrustProviderTests.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Net; -using System.Text.Json; -using DfE.FindInformationAcademiesTrusts.Data; -using DfE.FindInformationAcademiesTrusts.UnitTests.Mocks; -using static FluentAssertions.FluentActions; - -namespace DfE.FindInformationAcademiesTrusts.UnitTests; - -public class TrustProviderTests -{ - private readonly MockHttpClientFactory _mockHttpClientFactory; - private readonly MockLogger _mockLogger; - private const string TrustsEndpoint = "v3/trusts"; - private const string TrustEndpoint = "v3/trust/1234"; - - public TrustProviderTests() - { - _mockLogger = new MockLogger(); - _mockHttpClientFactory = new MockHttpClientFactory("AcademiesApi"); - } - - [Fact] - public async Task GetTrustsByUkprnAsync_should_return_a_trust_if_success_status() - { - var responseMessage = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent( - "{\"Data\": {\"GiasData\": {\"GroupName\": \"trust 1\", \"GroupType\": \"Multi-academy trust\", \"GroupContactAddress\": {\"Street\":\"12 Abbey Road\", \"Locality\": \"Dorthy Inlet\", \"AdditionalLine\": \"East Park\", \"Town\": \"Kingston upon Hull\", \"County\": \"East Riding of Yorkshire\", \"Postcode\": \"JY36 9VC\"}, \"ukprn\": \"1234\"}, \"Establishments\": []}}" - ) - }; - - _mockHttpClientFactory.SetUpHttpGetResponse(TrustEndpoint, responseMessage); - - var sut = new TrustProvider(_mockHttpClientFactory.Object, _mockLogger.Object); - - var result = await sut.GetTrustByUkprnAsync("1234"); - result.Should().BeEquivalentTo(new Trust("trust 1", - "1234", - "Multi-academy trust")); - } - - [Theory] - [InlineData( - "{\"Data\": {\"GiasData\": {\"GroupName\": \"trust 1\", \"GroupContactAddress\": {\"Street\":\"12 Abbey Road\", \"Locality\": \"Dorthy Inlet\", \"AdditionalLine\": \"East Park\", \"Town\": \"Kingston upon Hull\", \"County\": \"East Riding of Yorkshire\", \"Postcode\": \"JY36 9VC\"}, \"ukprn\": \"1234\"}, \"Establishments\": []}}", - "" - )] - [InlineData( - "{\"Data\": {\"GiasData\": {\"GroupName\": \"trust 1\", \"GroupType\": \"Single-academy trust\", \"GroupContactAddress\": {\"Street\":\"12 Abbey Road\", \"Locality\": \"Dorthy Inlet\", \"AdditionalLine\": \"East Park\", \"Town\": \"Kingston upon Hull\", \"County\": \"East Riding of Yorkshire\", \"Postcode\": \"JY36 9VC\"}, \"ukprn\": \"1234\"}, \"Establishments\": [ {\"Urn\": \"123\"}]}}", - "Single-academy trust" - )] - [InlineData( - "{\"Data\": {\"GiasData\": {\"GroupName\": \"trust 1\", \"GroupType\": \"Multi-academy trust\", \"GroupContactAddress\": {\"Street\":\"12 Abbey Road\", \"Locality\": \"Dorthy Inlet\", \"AdditionalLine\": \"East Park\", \"Town\": \"Kingston upon Hull\", \"County\": \"East Riding of Yorkshire\", \"Postcode\": \"JY36 9VC\"}, \"ukprn\": \"1234\"}, \"Establishments\": [{\"Urn\": \"123\"}, {\"Urn\": \"123\"}, {\"Urn\": \"123\"}]}}", - "Multi-academy trust" - )] - public async Task GetTrustByUkprnAsync_should_include_Trust_Type(string data, string expected) - { - var responseMessage = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(data) - }; - - _mockHttpClientFactory.SetUpHttpGetResponse(TrustEndpoint, responseMessage); - - var sut = new TrustProvider(_mockHttpClientFactory.Object, _mockLogger.Object); - - var result = await sut.GetTrustByUkprnAsync("1234"); - result?.Type.Should().Be(expected); - } - - [Fact] - public async Task GetTrustsByUkprnAsync_should_throw_exception_on_http_response_error_code() - { - var responseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError) - { Content = new StringContent("") }; - - _mockHttpClientFactory.SetUpHttpGetResponse(TrustEndpoint, responseMessage); - - var sut = new TrustProvider(_mockHttpClientFactory.Object, _mockLogger.Object); - - await Invoking(() => sut.GetTrustByUkprnAsync("1234")).Should().ThrowAsync() - .WithMessage("Problem communicating with Academies API"); - } - - [Theory] - [InlineData(HttpStatusCode.InternalServerError)] - [InlineData(HttpStatusCode.Unauthorized)] - [InlineData(HttpStatusCode.NotFound)] - public async Task GetTrustsByUkprnAsync_should_log_any_exception(HttpStatusCode statusCode) - { - var responseMessage = new HttpResponseMessage(statusCode) - { - Content = new StringContent("") - }; - - _mockHttpClientFactory.SetUpHttpGetResponse(TrustEndpoint, responseMessage); - - var sut = new TrustProvider(_mockHttpClientFactory.Object, _mockLogger.Object); - try - { - await sut.GetTrustByUkprnAsync("1234"); - } - catch - { - _mockLogger.VerifyLogError( - $"Received {statusCode} from Academies API, \r\nendpoint: https://apiendpoint.dev/v3/trust/1234"); - } - } - - [Theory] - [InlineData("{\"Data\": null }")] - [InlineData("{\"Data\": {\"GiasData\": null } }")] - [InlineData(null)] - public async Task GetTrustsByUkprnAsync_should_throw_exception_on_null_data_response(string? content) - { - var stringContent = content != null ? new StringContent(content) : null; - - var responseMessage = new HttpResponseMessage(HttpStatusCode.OK) - { Content = stringContent }; - - _mockHttpClientFactory.SetUpHttpGetResponse(TrustEndpoint, responseMessage); - - var sut = new TrustProvider(_mockHttpClientFactory.Object, _mockLogger.Object); - - await Invoking(() => sut.GetTrustByUkprnAsync("1234")).Should().ThrowAsync(); - } - - [Fact] - public async Task GetTrustsByUkprnAsync_should_return_null_on_Not_Found_Result() - { - var responseMessage = new HttpResponseMessage(HttpStatusCode.NotFound) - { - Content = new StringContent("") - }; - - _mockHttpClientFactory.SetUpHttpGetResponse(TrustEndpoint, responseMessage); - - var sut = new TrustProvider(_mockHttpClientFactory.Object, _mockLogger.Object); - var result = await sut.GetTrustByUkprnAsync("1234"); - result.Should().BeNull(); - } -} From cea66775283ce5967ad6419f1599645f56a419a5 Mon Sep 17 00:00:00 2001 From: Sara Gowen <9001998+dynamictulip@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:50:17 +0100 Subject: [PATCH 3/5] Change `TrustSearch` to use async entity framework Also change `TrustSearch` to use new async-compatible mocks --- .../TrustSearch.cs | 16 +++---- .../ITrustSearch.cs | 2 +- .../Mocks/MockDbContext.cs | 30 ------------ .../TrustSearchTests.cs | 47 +++++-------------- 4 files changed, 20 insertions(+), 75 deletions(-) delete mode 100644 tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbContext.cs diff --git a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustSearch.cs b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustSearch.cs index b043167f9..cefa615ee 100644 --- a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustSearch.cs +++ b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustSearch.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore; namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb; @@ -19,16 +20,14 @@ public TrustSearch(IAcademiesDbContext academiesDbContext, ITrustHelper trustHel _academiesDbContext = academiesDbContext; } - public Task> SearchAsync(string searchTerm) + public async Task SearchAsync(string searchTerm) { if (string.IsNullOrWhiteSpace(searchTerm)) { - return Task.FromResult( - Array.Empty().AsEnumerable() - ); + return Array.Empty(); } - var trustSearchEntries = _academiesDbContext.Groups + var trustSearchEntries = await _academiesDbContext.Groups .Where(g => g.GroupUid != null && g.GroupId != null && @@ -42,11 +41,8 @@ public Task> SearchAsync(string searchTerm) .Take(20) .Select(g => new TrustSearchEntry(g.GroupName!, _trustHelper.BuildAddressString(g), g.GroupUid!, g.GroupId!)) - .AsEnumerable(); + .ToArrayAsync(); - - return Task.FromResult( - trustSearchEntries - ); + return trustSearchEntries; } } diff --git a/DfE.FindInformationAcademiesTrusts.Data/ITrustSearch.cs b/DfE.FindInformationAcademiesTrusts.Data/ITrustSearch.cs index cf3fe738e..e4341f3e4 100644 --- a/DfE.FindInformationAcademiesTrusts.Data/ITrustSearch.cs +++ b/DfE.FindInformationAcademiesTrusts.Data/ITrustSearch.cs @@ -2,5 +2,5 @@ namespace DfE.FindInformationAcademiesTrusts.Data; public interface ITrustSearch { - public Task> SearchAsync(string searchTerm); + public Task SearchAsync(string searchTerm); } diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbContext.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbContext.cs deleted file mode 100644 index dc4a5a03f..000000000 --- a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Mocks/MockDbContext.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests.Mocks; - -public class MockDbContext -{ - public static DbSet GetMock(List lstData) where TData : class - { - var lstDataQueryable = lstData.AsQueryable(); - var dbSetMock = new Mock>(); - - dbSetMock.As>().Setup(s => s.Provider).Returns(lstDataQueryable.Provider); - dbSetMock.As>().Setup(s => s.Expression).Returns(lstDataQueryable.Expression); - dbSetMock.As>().Setup(s => s.ElementType).Returns(lstDataQueryable.ElementType); - dbSetMock.As>().Setup(s => s.GetEnumerator()).Returns(() => lstDataQueryable.GetEnumerator()); - dbSetMock.Setup(x => x.Add(It.IsAny())).Callback(lstData.Add); - dbSetMock.Setup(x => x.AddRange(It.IsAny>())).Callback>(lstData.AddRange); - dbSetMock.Setup(x => x.Remove(It.IsAny())).Callback(t => lstData.Remove(t)); - dbSetMock.Setup(x => x.RemoveRange(It.IsAny>())).Callback>(ts => - { - foreach (var t in ts) - { - lstData.Remove(t); - } - }); - - - return dbSetMock.Object; - } -} diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustSearchTests.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustSearchTests.cs index 18e027eec..2df0d3cb7 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustSearchTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustSearchTests.cs @@ -1,4 +1,3 @@ -using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.Models; using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests.Mocks; namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests; @@ -6,15 +5,15 @@ namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests; public class TrustSearchTests { private readonly ITrustSearch _sut; - private readonly Mock _mockAcademiesDbContext; + private readonly MockAcademiesDbContext _mockAcademiesDbContext; private readonly Mock _mockTrustHelper; public TrustSearchTests() { - _mockAcademiesDbContext = new Mock(); + _mockAcademiesDbContext = new MockAcademiesDbContext(); _mockTrustHelper = new Mock(); - SetupMockDbContextGroups(3); + _mockAcademiesDbContext.SetupMockDbContextGroups(3); _sut = new TrustSearch(_mockAcademiesDbContext.Object, _mockTrustHelper.Object); } @@ -25,7 +24,7 @@ public TrustSearchTests() [InlineData(30)] public async Task SearchAsync_should_only_return_20_results_when_there_are_more_than_20_matches(int numMatches) { - SetupMockDbContextGroups(numMatches); + _mockAcademiesDbContext.SetupMockDbContextGroups(numMatches); var result = await _sut.SearchAsync("trust"); result.Should().HaveCount(20); @@ -34,7 +33,7 @@ public async Task SearchAsync_should_only_return_20_results_when_there_are_more_ [Fact] public async Task SearchAsync_should_return_all_results_when_there_are_less_than_20_matches() { - SetupMockDbContextGroups(19); + _mockAcademiesDbContext.SetupMockDbContextGroups(19); var result = await _sut.SearchAsync("trust"); result.Should().HaveCount(19); @@ -78,7 +77,7 @@ public async Task SearchAsync_should_return_trust_with_GroupId() [Fact] public async Task SearchAsync_should_return_trust_address_formatted_as_string() { - var groups = SetupMockDbContextGroups(3); + var groups = _mockAcademiesDbContext.SetupMockDbContextGroups(3); var fakeTrusts = new[] { "12 Abbey Road, Dorthy Inlet, East Park, Kingston upon Hull, JY36 9VC", @@ -125,16 +124,13 @@ public async Task SearchAsync_should_not_call_database_if_empty_search_term(stri [Fact] public async Task SearchAsync_should_return_trusts_sorted_alphabetically_by_trust_name() { + var groups = _mockAcademiesDbContext.SetupMockDbContextGroups(5); var names = new[] { "education", "abbey", "educations", "aldridge trust", "abbey trust" }; - var groups = new List(); - foreach (var name in names) + for (var i = 0; i < names.Length; i++) { - groups.Add(new Group { GroupName = name }); + groups[i].GroupName = names[i]; } - _mockAcademiesDbContext.Setup(academiesDbContext => academiesDbContext.Groups) - .Returns(MockDbContext.GetMock(groups)); - var result = await _sut.SearchAsync("a"); result.Should().BeInAscendingOrder(t => t.Name); } @@ -142,7 +138,7 @@ public async Task SearchAsync_should_return_trusts_sorted_alphabetically_by_trus [Fact] public async Task SearchAsync_should_only_return_single_and_multi_academy_trusts() { - var groups = SetupMockDbContextGroups(5); + var groups = _mockAcademiesDbContext.SetupMockDbContextGroups(5); groups[0].GroupType = "Federation"; groups[1].GroupType = "Single-academy trust"; @@ -157,7 +153,7 @@ public async Task SearchAsync_should_only_return_single_and_multi_academy_trusts [Fact] public async Task SearchAsync_should_not_return_groups_with_a_null_GroupUid() { - var groups = SetupMockDbContextGroups(5); + var groups = _mockAcademiesDbContext.SetupMockDbContextGroups(5); groups[0].GroupUid = null; @@ -168,7 +164,7 @@ public async Task SearchAsync_should_not_return_groups_with_a_null_GroupUid() [Fact] public async Task SearchAsync_should_not_return_groups_with_a_null_GroupId() { - var groups = SetupMockDbContextGroups(5); + var groups = _mockAcademiesDbContext.SetupMockDbContextGroups(5); groups[0].GroupId = null; @@ -179,28 +175,11 @@ public async Task SearchAsync_should_not_return_groups_with_a_null_GroupId() [Fact] public async Task SearchAsync_should_not_return_groups_with_a_null_GroupName() { - var groups = SetupMockDbContextGroups(5); + var groups = _mockAcademiesDbContext.SetupMockDbContextGroups(5); groups[0].GroupName = null; var result = await _sut.SearchAsync("trust"); result.Should().HaveCount(4); } - - private List SetupMockDbContextGroups(int numMatches) - { - var groups = new List(); - for (var i = 0; i < numMatches; i++) - { - groups.Add(new Group - { - GroupName = $"trust {i}", GroupUid = $"{i}", GroupId = $"TR0{i}", GroupType = "Multi-academy trust" - }); - } - - _mockAcademiesDbContext.Setup(academiesDbContext => academiesDbContext.Groups) - .Returns(MockDbContext.GetMock(groups)); - - return groups; - } } From 7b162b95abd001fb6a9288745005bab392042680 Mon Sep 17 00:00:00 2001 From: danielryannimble Date: Fri, 13 Oct 2023 13:20:17 +0100 Subject: [PATCH 4/5] Removal of references to ukprn from code base the GroupUid will be used as the primary reference number when retrieving trusts. ukprn will still be a value returned and references to it will remain, just not used as a primary key. --- .../TrustProvider.cs | 5 +++-- .../ITrustProvider.cs | 2 +- .../Trust.cs | 2 +- .../Pages/Search.cshtml.cs | 2 +- .../Pages/Trusts/Contacts.cshtml.cs | 2 +- .../Pages/Trusts/Details.cshtml.cs | 2 +- .../Pages/Trusts/_TrustNavigation.cshtml | 4 ++-- .../TrustProviderTests.cs | 10 +++++----- .../Pages/SearchModelTests.cs | 18 +++++++++--------- .../Pages/Trusts/ContactsModelTests.cs | 14 +++++++------- .../Pages/Trusts/DetailsModelTests.cs | 12 ++++++------ 11 files changed, 37 insertions(+), 36 deletions(-) diff --git a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs index 5653bed9d..a210af63f 100644 --- a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs +++ b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs @@ -17,7 +17,7 @@ public TrustProvider(IAcademiesDbContext academiesDbContext) _academiesDbContext = academiesDbContext; } - public async Task GetTrustByUkprnAsync(string groupUid) + public async Task GetTrustByGroupUidAsync(string groupUid) { Trust? trust = null; @@ -25,7 +25,8 @@ public TrustProvider(IAcademiesDbContext academiesDbContext) if (group is not null) { trust = new Trust( - group.GroupName, + group.GroupUid!, + group.GroupName ?? string.Empty, group.Ukprn, group.GroupType ?? string.Empty ); diff --git a/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs b/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs index 9a080a120..83f16fd69 100644 --- a/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs +++ b/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs @@ -2,5 +2,5 @@ namespace DfE.FindInformationAcademiesTrusts.Data; public interface ITrustProvider { - public Task GetTrustByUkprnAsync(string groupUid); + public Task GetTrustByGroupUidAsync(string groupUid); } diff --git a/DfE.FindInformationAcademiesTrusts.Data/Trust.cs b/DfE.FindInformationAcademiesTrusts.Data/Trust.cs index 18320356e..62025521b 100644 --- a/DfE.FindInformationAcademiesTrusts.Data/Trust.cs +++ b/DfE.FindInformationAcademiesTrusts.Data/Trust.cs @@ -1,3 +1,3 @@ namespace DfE.FindInformationAcademiesTrusts.Data; -public record Trust(string Name, string? Ukprn, string Type); +public record Trust(string GroupUid, string Name, string? Ukprn, string Type); diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs index 9ff4e14ab..3c1818820 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs +++ b/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs @@ -27,7 +27,7 @@ public async Task OnGetAsync() { if (!string.IsNullOrWhiteSpace(TrustId)) { - var trust = await _trustProvider.GetTrustByUkprnAsync(TrustId); + var trust = await _trustProvider.GetTrustByGroupUidAsync(TrustId); if (trust != null && string.Equals(trust.Name, KeyWords, StringComparison.CurrentCultureIgnoreCase)) { return RedirectToPage("/Trusts/Details", new { Uid = TrustId }); diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs index fcf27ab6e..87c9086f1 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs +++ b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs @@ -20,7 +20,7 @@ public ContactsModel(ITrustProvider trustProvider) public async Task OnGetAsync() { - var trust = await _trustProvider.GetTrustByUkprnAsync(Uid); + var trust = await _trustProvider.GetTrustByGroupUidAsync(Uid); if (trust == null) { diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs index 7eac129c8..230c65782 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs +++ b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs @@ -21,7 +21,7 @@ public DetailsModel(ITrustProvider trustProvider) public async Task OnGetAsync() { - var trust = await _trustProvider.GetTrustByUkprnAsync(Uid); + var trust = await _trustProvider.GetTrustByGroupUidAsync(Uid); if (trust == null) { diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml index db6431470..416a01f07 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml +++ b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml @@ -19,12 +19,12 @@
@ViewConstants.AboutTheTrustSectionName
  • - + TrustDetails
  • - + TrustContacts
  • diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs index 426871776..72d426fcd 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs @@ -16,22 +16,22 @@ public TrustProviderTests() } [Fact] - public async Task GetTrustsByUkprnAsync_should_return_a_trust_if_group_found() + public async Task GetTrustsByGroupUidAsync_should_return_a_trust_if_group_found() { _groups.Add(new Group { GroupName = "trust 1", GroupUid = "1234", GroupType = "Multi-academy trust", Ukprn = "my ukprn" }); - var result = await _sut.GetTrustByUkprnAsync("1234"); + var result = await _sut.GetTrustByGroupUidAsync("1234"); - result.Should().BeEquivalentTo(new Trust("trust 1", + result.Should().BeEquivalentTo(new Trust("1234", "trust 1", "my ukprn", "Multi-academy trust")); } [Fact] - public async Task GetTrustsByUkprnAsync_should_return_null_when_group_not_found() + public async Task GetTrustsByGroupUidAsync_should_return_null_when_group_not_found() { - var result = await _sut.GetTrustByUkprnAsync("987654321"); + var result = await _sut.GetTrustByGroupUidAsync("987654321"); result.Should().BeNull(); } } diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs index 09a98d9a8..45abfcb4c 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs @@ -27,9 +27,9 @@ public SearchModelTests() }; private readonly Trust _fakeTrust = - new("trust 1", "2044", "Multi-academy trust"); + new("123", "trust 1", "2044", "Multi-academy trust"); - private const string _trustId = "1234"; + private const string TrustId = "1234"; [Fact] public async Task OnGetAsync_should_search_if_query_parameter() @@ -55,9 +55,9 @@ public async Task OnGetAsync_should_default_to_empty_trusts_if_no_query() [Fact] public async Task OnGetAsync_should_redirect_to_trust_details_if_given_trustId() { - _sut.TrustId = _trustId; + _sut.TrustId = TrustId; _sut.KeyWords = "trust 1"; - _mockTrustProvider.Setup(s => s.GetTrustByUkprnAsync(_trustId).Result) + _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync(TrustId).Result) .Returns(_fakeTrust); var result = await _sut.OnGetAsync(); @@ -70,16 +70,16 @@ public async Task OnGetAsync_should_redirect_to_trust_details_if_given_trustId() [Fact] public async Task OnGetAsync_should_pass_trustId_to_trust_details_if_given_trustId() { - _sut.TrustId = _trustId; + _sut.TrustId = TrustId; _sut.KeyWords = "trust 1"; - _mockTrustProvider.Setup(s => s.GetTrustByUkprnAsync(_trustId).Result) + _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync(TrustId).Result) .Returns(_fakeTrust); var result = await _sut.OnGetAsync(); result.Should().BeOfType(); var redirectResult = (RedirectToPageResult)result; - redirectResult.RouteValues.Should().ContainKey("Uid").WhoseValue.Should().Be(_trustId); + redirectResult.RouteValues.Should().ContainKey("Uid").WhoseValue.Should().Be(TrustId); } [Fact] @@ -88,12 +88,12 @@ public async Task OnGetAsync_should_not_redirect_to_trust_details_if_trustId_doe const string query = "trust 3"; _mockTrustSearch.Setup(s => s.SearchAsync(query).Result).Returns(_fakeTrusts); - _mockTrustProvider.Setup(s => s.GetTrustByUkprnAsync(_trustId).Result) + _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync(TrustId).Result) .Returns(_fakeTrust); _mockTrustSearch.Setup(s => s.SearchAsync(query).Result).Returns(_fakeTrusts); _sut.KeyWords = query; - _sut.TrustId = _trustId; + _sut.TrustId = TrustId; var result = await _sut.OnGetAsync(); diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs index 92cf865fb..3ed50797e 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs @@ -16,17 +16,17 @@ public ContactsModelTests() } [Fact] - public async void OnGetAsync_should_fetch_a_trust_by_ukprn() + public async void OnGetAsync_should_fetch_a_trust_by_GroupUid() { - _mockTrustProvider.Setup(s => s.GetTrustByUkprnAsync("1234").Result) - .Returns(new Trust("test", "test", "Multi-academy trust")); + _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1234").Result) + .Returns(new Trust("test", "test", "test", "Multi-academy trust")); _sut.Uid = "1234"; await _sut.OnGetAsync(); - _sut.Trust.Should().BeEquivalentTo(new Trust("test", "test", "Multi-academy trust")); + _sut.Trust.Should().BeEquivalentTo(new Trust("test", "test", "test", "Multi-academy trust")); } [Fact] - public async void Ukprn_should_be_empty_string_by_default() + public async void GroupUid_should_be_empty_string_by_default() { await _sut.OnGetAsync(); _sut.Uid.Should().BeEquivalentTo(string.Empty); @@ -47,7 +47,7 @@ public void PageSection_should_be_AboutTheTrust() [Fact] public async void OnGetAsync_should_return_not_found_result_if_trust_is_not_found() { - _mockTrustProvider.Setup(s => s.GetTrustByUkprnAsync("1111").Result) + _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1111").Result) .Returns((Trust?)null); _sut.Uid = "1111"; @@ -57,7 +57,7 @@ public async void OnGetAsync_should_return_not_found_result_if_trust_is_not_foun } [Fact] - public async void OnGetAsync_should_return_not_found_result_if_Ukprn_is_not_provided() + public async void OnGetAsync_should_return_not_found_result_if_GroupUid_is_not_provided() { var result = await _sut.OnGetAsync(); result.Should().BeOfType(); diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs index 717fb9250..26a3ecca9 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs @@ -16,18 +16,18 @@ public DetailsModelTests() } [Fact] - public async void OnGetAsync_should_fetch_a_trust_by_ukprn() + public async void OnGetAsync_should_fetch_a_trust_by_groupUid() { - _mockTrustProvider.Setup(s => s.GetTrustByUkprnAsync("1234").Result) - .Returns(new Trust("test", "test", "Multi-academy trust")); + _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1234").Result) + .Returns(new Trust("test", "test", "test", "Multi-academy trust")); _sut.Uid = "1234"; await _sut.OnGetAsync(); - _sut.Trust.Should().BeEquivalentTo(new Trust("test", "test", "Multi-academy trust")); + _sut.Trust.Should().BeEquivalentTo(new Trust("test", "test", "test", "Multi-academy trust")); } [Fact] - public async void Ukprn_should_be_empty_string_by_default() + public async void GroupUid_should_be_empty_string_by_default() { await _sut.OnGetAsync(); _sut.Uid.Should().BeEquivalentTo(string.Empty); @@ -48,7 +48,7 @@ public void PageSection_should_be_AboutTheTrust() [Fact] public async void OnGetAsync_should_return_not_found_result_if_trust_is_not_found() { - _mockTrustProvider.Setup(s => s.GetTrustByUkprnAsync("1111").Result) + _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1111").Result) .Returns((Trust?)null); _sut.Uid = "1111"; From 3c803f707cf6d3522d134c0e3e8b6709c2a6b806 Mon Sep 17 00:00:00 2001 From: Sara Gowen <9001998+dynamictulip@users.noreply.github.com> Date: Fri, 13 Oct 2023 17:01:28 +0100 Subject: [PATCH 5/5] Replace `GroupUid` with `Uid` outside academies db project We want to keep our language in the web project consistent with that of our users in order to make the system easier to maintain - we'd started to drift already with `GroupUid`, `Uid` and `TrustId` all meaning the same thing. `GroupUid` is language specific to the academies database so we will keep it there and use `Uid` in all other scenarios. Also refactored `SearchModelTests` --- .../TrustProvider.cs | 4 +- .../ITrustProvider.cs | 2 +- .../Trust.cs | 2 +- .../Pages/Search.cshtml.cs | 8 +-- .../Pages/Trusts/Contacts.cshtml.cs | 2 +- .../Pages/Trusts/Details.cshtml.cs | 2 +- .../Pages/Trusts/_TrustNavigation.cshtml | 4 +- .../TrustProviderTests.cs | 8 +-- .../Pages/SearchModelTests.cs | 68 ++++++++----------- .../Pages/Trusts/ContactsModelTests.cs | 10 +-- .../Pages/Trusts/DetailsModelTests.cs | 8 +-- 11 files changed, 54 insertions(+), 64 deletions(-) diff --git a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs index a210af63f..9068c9648 100644 --- a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs +++ b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/TrustProvider.cs @@ -17,11 +17,11 @@ public TrustProvider(IAcademiesDbContext academiesDbContext) _academiesDbContext = academiesDbContext; } - public async Task GetTrustByGroupUidAsync(string groupUid) + public async Task GetTrustByUidAsync(string uid) { Trust? trust = null; - var group = await _academiesDbContext.Groups.SingleOrDefaultAsync(g => g.GroupUid == groupUid); + var group = await _academiesDbContext.Groups.SingleOrDefaultAsync(g => g.GroupUid == uid); if (group is not null) { trust = new Trust( diff --git a/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs b/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs index 83f16fd69..b36029e8e 100644 --- a/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs +++ b/DfE.FindInformationAcademiesTrusts.Data/ITrustProvider.cs @@ -2,5 +2,5 @@ namespace DfE.FindInformationAcademiesTrusts.Data; public interface ITrustProvider { - public Task GetTrustByGroupUidAsync(string groupUid); + public Task GetTrustByUidAsync(string uid); } diff --git a/DfE.FindInformationAcademiesTrusts.Data/Trust.cs b/DfE.FindInformationAcademiesTrusts.Data/Trust.cs index 62025521b..f8e61fd94 100644 --- a/DfE.FindInformationAcademiesTrusts.Data/Trust.cs +++ b/DfE.FindInformationAcademiesTrusts.Data/Trust.cs @@ -1,3 +1,3 @@ namespace DfE.FindInformationAcademiesTrusts.Data; -public record Trust(string GroupUid, string Name, string? Ukprn, string Type); +public record Trust(string Uid, string Name, string? Ukprn, string Type); diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs index 3c1818820..a32126ebd 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs +++ b/DfE.FindInformationAcademiesTrusts/Pages/Search.cshtml.cs @@ -20,17 +20,17 @@ public SearchModel(ITrustProvider trustProvider, ITrustSearch trustSearch) public string InputId => "search"; [BindProperty(SupportsGet = true)] public string KeyWords { get; set; } = string.Empty; - [BindProperty(SupportsGet = true)] public string TrustId { get; set; } = string.Empty; + [BindProperty(SupportsGet = true)] public string Uid { get; set; } = string.Empty; public IEnumerable Trusts { get; set; } = Array.Empty(); public async Task OnGetAsync() { - if (!string.IsNullOrWhiteSpace(TrustId)) + if (!string.IsNullOrWhiteSpace(Uid)) { - var trust = await _trustProvider.GetTrustByGroupUidAsync(TrustId); + var trust = await _trustProvider.GetTrustByUidAsync(Uid); if (trust != null && string.Equals(trust.Name, KeyWords, StringComparison.CurrentCultureIgnoreCase)) { - return RedirectToPage("/Trusts/Details", new { Uid = TrustId }); + return RedirectToPage("/Trusts/Details", new { Uid }); } } diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs index 87c9086f1..a88d3e094 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs +++ b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs @@ -20,7 +20,7 @@ public ContactsModel(ITrustProvider trustProvider) public async Task OnGetAsync() { - var trust = await _trustProvider.GetTrustByGroupUidAsync(Uid); + var trust = await _trustProvider.GetTrustByUidAsync(Uid); if (trust == null) { diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs index 230c65782..3dd16a01a 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs +++ b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Details.cshtml.cs @@ -21,7 +21,7 @@ public DetailsModel(ITrustProvider trustProvider) public async Task OnGetAsync() { - var trust = await _trustProvider.GetTrustByGroupUidAsync(Uid); + var trust = await _trustProvider.GetTrustByUidAsync(Uid); if (trust == null) { diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml index 416a01f07..ba6c07791 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml +++ b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/_TrustNavigation.cshtml @@ -19,12 +19,12 @@
    @ViewConstants.AboutTheTrustSectionName
    • - + TrustDetails
    • - + TrustContacts
    • diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs index 72d426fcd..8e27be99c 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/TrustProviderTests.cs @@ -16,12 +16,12 @@ public TrustProviderTests() } [Fact] - public async Task GetTrustsByGroupUidAsync_should_return_a_trust_if_group_found() + public async Task GetTrustsByUidAsync_should_return_a_trust_if_group_found() { _groups.Add(new Group { GroupName = "trust 1", GroupUid = "1234", GroupType = "Multi-academy trust", Ukprn = "my ukprn" }); - var result = await _sut.GetTrustByGroupUidAsync("1234"); + var result = await _sut.GetTrustByUidAsync("1234"); result.Should().BeEquivalentTo(new Trust("1234", "trust 1", "my ukprn", @@ -29,9 +29,9 @@ public async Task GetTrustsByGroupUidAsync_should_return_a_trust_if_group_found( } [Fact] - public async Task GetTrustsByGroupUidAsync_should_return_null_when_group_not_found() + public async Task GetTrustsByUidAsync_should_return_null_when_group_not_found() { - var result = await _sut.GetTrustByGroupUidAsync("987654321"); + var result = await _sut.GetTrustByUidAsync("987654321"); result.Should().BeNull(); } } diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs index 45abfcb4c..62862ccf6 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/SearchModelTests.cs @@ -7,18 +7,10 @@ namespace DfE.FindInformationAcademiesTrusts.UnitTests.Pages; public class SearchModelTests { - private readonly Mock _mockTrustProvider; + private const string SearchTermThatMatchesAllFakeTrusts = "trust"; private readonly SearchModel _sut; private readonly Mock _mockTrustSearch; - public SearchModelTests() - { - _mockTrustProvider = new Mock(); - _mockTrustSearch = new Mock(); - - _sut = new SearchModel(_mockTrustProvider.Object, _mockTrustSearch.Object); - } - private readonly TrustSearchEntry[] _fakeTrusts = { new("trust 1", "Dorthy Inlet, Kingston upon Hull, City of, JY36 9VC", "2044", ""), @@ -27,17 +19,24 @@ public SearchModelTests() }; private readonly Trust _fakeTrust = - new("123", "trust 1", "2044", "Multi-academy trust"); + new("2044", "trust 1", "100123456", "Multi-academy trust"); - private const string TrustId = "1234"; + public SearchModelTests() + { + Mock mockTrustProvider = new(); + _mockTrustSearch = new Mock(); + + mockTrustProvider.Setup(s => s.GetTrustByUidAsync(_fakeTrust.Uid).Result) + .Returns(_fakeTrust); + _mockTrustSearch.Setup(s => s.SearchAsync(SearchTermThatMatchesAllFakeTrusts).Result).Returns(_fakeTrusts); + + _sut = new SearchModel(mockTrustProvider.Object, _mockTrustSearch.Object); + } [Fact] - public async Task OnGetAsync_should_search_if_query_parameter() + public async Task OnGetAsync_should_search_if_query_parameter_provided() { - const string query = "trust"; - - _mockTrustSearch.Setup(s => s.SearchAsync(query).Result).Returns(_fakeTrusts); - _sut.KeyWords = query; + _sut.KeyWords = SearchTermThatMatchesAllFakeTrusts; await _sut.OnGetAsync(); @@ -53,12 +52,10 @@ public async Task OnGetAsync_should_default_to_empty_trusts_if_no_query() } [Fact] - public async Task OnGetAsync_should_redirect_to_trust_details_if_given_trustId() + public async Task OnGetAsync_should_redirect_to_trust_details_if_given_uid_and_query_is_trust_name() { - _sut.TrustId = TrustId; - _sut.KeyWords = "trust 1"; - _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync(TrustId).Result) - .Returns(_fakeTrust); + _sut.Uid = _fakeTrust.Uid; + _sut.KeyWords = _fakeTrust.Name; var result = await _sut.OnGetAsync(); @@ -70,43 +67,36 @@ public async Task OnGetAsync_should_redirect_to_trust_details_if_given_trustId() [Fact] public async Task OnGetAsync_should_pass_trustId_to_trust_details_if_given_trustId() { - _sut.TrustId = TrustId; - _sut.KeyWords = "trust 1"; - _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync(TrustId).Result) - .Returns(_fakeTrust); + _sut.Uid = _fakeTrust.Uid; + _sut.KeyWords = _fakeTrust.Name; var result = await _sut.OnGetAsync(); result.Should().BeOfType(); var redirectResult = (RedirectToPageResult)result; - redirectResult.RouteValues.Should().ContainKey("Uid").WhoseValue.Should().Be(TrustId); + redirectResult.RouteValues.Should().ContainKey("Uid").WhoseValue.Should().Be(_fakeTrust.Uid); } [Fact] public async Task OnGetAsync_should_not_redirect_to_trust_details_if_trustId_does_not_match_query() { - const string query = "trust 3"; - - _mockTrustSearch.Setup(s => s.SearchAsync(query).Result).Returns(_fakeTrusts); - _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync(TrustId).Result) - .Returns(_fakeTrust); + var differentFakeTrust = new TrustSearchEntry("other trust", "Some address", "987", "TR0987"); + _mockTrustSearch.Setup(s => s.SearchAsync(differentFakeTrust.Name).Result) + .Returns(new[] { differentFakeTrust }); - _mockTrustSearch.Setup(s => s.SearchAsync(query).Result).Returns(_fakeTrusts); - _sut.KeyWords = query; - _sut.TrustId = TrustId; + _sut.KeyWords = differentFakeTrust.Name; + _sut.Uid = _fakeTrust.Uid; var result = await _sut.OnGetAsync(); result.Should().BeOfType(); - _sut.Trusts.Should().BeEquivalentTo(_fakeTrusts); + _sut.Trusts.Should().ContainSingle(t => t == differentFakeTrust); } [Fact] public async Task OnGetPopulateAutocompleteAsync_should_return_trusts_matching_keyword() { - const string query = "trust"; - _mockTrustSearch.Setup(s => s.SearchAsync(query).Result).Returns(_fakeTrusts); - _sut.KeyWords = query; + _sut.KeyWords = SearchTermThatMatchesAllFakeTrusts; var result = await _sut.OnGetPopulateAutocompleteAsync(); @@ -129,7 +119,7 @@ public void KeyWords_property_is_empty_by_default() [Fact] public void TrustId_property_is_empty_by_default() { - _sut.TrustId.Should().Be(""); + _sut.Uid.Should().Be(""); } [Fact] diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs index 3ed50797e..7b37772b4 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/ContactsModelTests.cs @@ -16,9 +16,9 @@ public ContactsModelTests() } [Fact] - public async void OnGetAsync_should_fetch_a_trust_by_GroupUid() + public async void OnGetAsync_should_fetch_a_trust_by_Uid() { - _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1234").Result) + _mockTrustProvider.Setup(s => s.GetTrustByUidAsync("1234").Result) .Returns(new Trust("test", "test", "test", "Multi-academy trust")); _sut.Uid = "1234"; await _sut.OnGetAsync(); @@ -26,7 +26,7 @@ public async void OnGetAsync_should_fetch_a_trust_by_GroupUid() } [Fact] - public async void GroupUid_should_be_empty_string_by_default() + public async void Uid_should_be_empty_string_by_default() { await _sut.OnGetAsync(); _sut.Uid.Should().BeEquivalentTo(string.Empty); @@ -47,7 +47,7 @@ public void PageSection_should_be_AboutTheTrust() [Fact] public async void OnGetAsync_should_return_not_found_result_if_trust_is_not_found() { - _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1111").Result) + _mockTrustProvider.Setup(s => s.GetTrustByUidAsync("1111").Result) .Returns((Trust?)null); _sut.Uid = "1111"; @@ -57,7 +57,7 @@ public async void OnGetAsync_should_return_not_found_result_if_trust_is_not_foun } [Fact] - public async void OnGetAsync_should_return_not_found_result_if_GroupUid_is_not_provided() + public async void OnGetAsync_should_return_not_found_result_if_Uid_is_not_provided() { var result = await _sut.OnGetAsync(); result.Should().BeOfType(); diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs index 26a3ecca9..d2010703a 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Trusts/DetailsModelTests.cs @@ -16,9 +16,9 @@ public DetailsModelTests() } [Fact] - public async void OnGetAsync_should_fetch_a_trust_by_groupUid() + public async void OnGetAsync_should_fetch_a_trust_by_uid() { - _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1234").Result) + _mockTrustProvider.Setup(s => s.GetTrustByUidAsync("1234").Result) .Returns(new Trust("test", "test", "test", "Multi-academy trust")); _sut.Uid = "1234"; @@ -48,7 +48,7 @@ public void PageSection_should_be_AboutTheTrust() [Fact] public async void OnGetAsync_should_return_not_found_result_if_trust_is_not_found() { - _mockTrustProvider.Setup(s => s.GetTrustByGroupUidAsync("1111").Result) + _mockTrustProvider.Setup(s => s.GetTrustByUidAsync("1111").Result) .Returns((Trust?)null); _sut.Uid = "1111"; @@ -57,7 +57,7 @@ public async void OnGetAsync_should_return_not_found_result_if_trust_is_not_foun } [Fact] - public async void OnGetAsync_should_return_not_found_result_if_Ukprn_is_not_provided() + public async void OnGetAsync_should_return_not_found_result_if_Uid_is_not_provided() { var result = await _sut.OnGetAsync(); result.Should().BeOfType();