Skip to content

Commit 69e95f6

Browse files
committed
Add tests
1 parent 4dce51a commit 69e95f6

33 files changed

+685
-114
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="FluentAssertions" Version="5.10.3" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
12+
<PackageReference Include="Moq" Version="4.14.6" />
13+
<PackageReference Include="xunit" Version="2.4.0" />
14+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
15+
<PackageReference Include="coverlet.collector" Version="1.2.0" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<ProjectReference Include="..\Refactoring.Web\Refactoring.Web.csproj" />
20+
</ItemGroup>
21+
22+
<ItemGroup>
23+
<Folder Include="Tests\Services\Helpers" />
24+
</ItemGroup>
25+
26+
</Project>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System.Threading.Tasks;
2+
using FluentAssertions;
3+
using Moq;
4+
using Refactoring.Web.DomainModels;
5+
using Refactoring.Web.Services;
6+
using Refactoring.Web.Services.Interfaces;
7+
using Refactoring.Web.Services.OrderProcessors;
8+
using Xunit;
9+
10+
namespace Refactoring.Tests.Tests.Services.OrderProcessors {
11+
public class TestCambridgeOrderProcessor {
12+
[Fact]
13+
public async void GivenDateIsTuesday_ImageUrl_Set_OnOrderAdvert() {
14+
// Arrange
15+
var testOrder = new Order {
16+
Id = "foo"
17+
};
18+
var fakeAdvertPrinter= new Mock<IAdvertPrinter>();
19+
20+
var fakeDateTimeResolver = new Mock<IDateTimeResolver>();
21+
fakeDateTimeResolver.Setup(m => m.IsItTuesday()).Returns(true);
22+
23+
var fakeChamberOfCommerceApi = new Mock<IChamberOfCommerceApi>();
24+
var fakeDataResult = new DataResult {
25+
ThumbnailUrl = "http://example.com/some_thumbnail.png",
26+
Title = "My Title..."
27+
};
28+
fakeChamberOfCommerceApi
29+
.Setup(m => m.GetImageAndThumbnailDataFor(It.IsAny<string>()))
30+
.Returns(Task.FromResult(fakeDataResult));
31+
32+
var sut = new CambridgeOrderProcessor(
33+
fakeChamberOfCommerceApi.Object,
34+
fakeAdvertPrinter.Object,
35+
fakeDateTimeResolver.Object);
36+
37+
// Act
38+
var result = await sut.PrintAdvertAndUpdateOrder(testOrder);
39+
40+
// Assert
41+
result.Advert.ImageUrl.Should().Be(fakeDataResult.ThumbnailUrl);
42+
}
43+
44+
[Fact]
45+
public async void GivenDateIsNotTuesday_ImageUrl_NotSet_OnOrderAdvert() {
46+
// Arrange
47+
var testOrder = new Order {
48+
Id = "foo"
49+
};
50+
var fakeAdvertPrinter= new Mock<IAdvertPrinter>();
51+
52+
var fakeDateTimeResolver = new Mock<IDateTimeResolver>();
53+
fakeDateTimeResolver.Setup(m => m.IsItTuesday()).Returns(false);
54+
55+
var fakeChamberOfCommerceApi = new Mock<IChamberOfCommerceApi>();
56+
var fakeDataResult = new DataResult {
57+
ThumbnailUrl = "http://example.com/some_thumbnail.png",
58+
Title = "My Title..."
59+
};
60+
fakeChamberOfCommerceApi
61+
.Setup(m => m.GetImageAndThumbnailDataFor(It.IsAny<string>()))
62+
.Returns(Task.FromResult(fakeDataResult));
63+
64+
var sut = new CambridgeOrderProcessor(
65+
fakeChamberOfCommerceApi.Object,
66+
fakeAdvertPrinter.Object,
67+
fakeDateTimeResolver.Object);
68+
69+
// Act
70+
var result = await sut.PrintAdvertAndUpdateOrder(testOrder);
71+
72+
// Assert
73+
result.Advert.ImageUrl.Should().BeNull();
74+
}
75+
}
76+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using FluentAssertions;
4+
using Moq;
5+
using Refactoring.Web.DomainModels;
6+
using Refactoring.Web.Services.Interfaces;
7+
using Refactoring.Web.Services.OrderProcessors;
8+
using Xunit;
9+
10+
namespace Refactoring.Tests.Tests.Services.OrderProcessors {
11+
public class TestMiddletonOrderProcessor {
12+
[Theory]
13+
[InlineData(0.05, "Get 5.00% off your next purchase!")]
14+
[InlineData(0.08, "Get 8.00% off your next purchase!")]
15+
[InlineData(0.18, "Get 18.00% off your next purchase!")]
16+
public async Task Given_ItIsMorning_PrintAdvertAndUpdateOrder_Returns_Order_With_AdvertContent_AmDealRate(
17+
decimal inputDeal, string expectedContent) {
18+
// Arrange
19+
var testOrder = new Order {
20+
Id = "foo"
21+
};
22+
23+
var fakeDealService = new Mock<IDealService>();
24+
fakeDealService.Setup(m => m.GenerateDeal(It.IsAny<DateTime>()))
25+
.Returns(inputDeal);
26+
27+
var fakeChamberOfCommerce = new Mock<IChamberOfCommerceApi>();
28+
var fakePrinter = new Mock<IAdvertPrinter>();
29+
var fakeRandom = new Mock<IRandomHelper>();
30+
31+
var sut = new MiddletonOrderProcessor(
32+
fakeDealService.Object,
33+
fakeChamberOfCommerce.Object,
34+
fakePrinter.Object,
35+
fakeRandom.Object
36+
);
37+
38+
// Act
39+
var order = await sut.PrintAdvertAndUpdateOrder(testOrder);
40+
41+
// Assert
42+
order.Advert.Content.Should().Be(expectedContent);
43+
}
44+
}
45+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using FluentAssertions;
3+
using Refactoring.Web.Services;
4+
using Xunit;
5+
6+
namespace Refactoring.Tests.Tests.Services {
7+
public class TestDealService {
8+
[Fact]
9+
public void Given_MorningDateTime_GenerateDeal_Returns_AmRate() {
10+
// Arrange
11+
var sut = new DealService();
12+
var morningTime = new DateTime(2020, 10, 10, 10, 10, 10);
13+
var amRate = DealService.AmRate;
14+
15+
// Act
16+
var generatedDealRate = sut.GenerateDeal(morningTime);
17+
18+
// Assert
19+
generatedDealRate.Should().Be(amRate);
20+
}
21+
22+
[Fact]
23+
public void Given_EveningDateTime_GenerateDeal_Returns_PmRate() {
24+
// Arrange
25+
var sut = new DealService();
26+
var afternoonTime = new DateTime(2020, 10, 10, 20, 10, 10);
27+
var pmRate = DealService.PmRate;
28+
29+
// Act
30+
var generatedDealRate = sut.GenerateDeal(afternoonTime);
31+
32+
// Assert
33+
generatedDealRate.Should().Be(pmRate);
34+
}
35+
}
36+
}

Refactoring.Web/Controllers/HomeController.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1-
using System.Collections.Generic;
2-
using System.Diagnostics;
1+
using System.Diagnostics;
32
using System.Linq;
43
using Microsoft.AspNetCore.Mvc;
54
using Microsoft.AspNetCore.Mvc.Rendering;
65
using Microsoft.Extensions.Logging;
76
using Refactoring.Web.Models;
7+
using Refactoring.Web.Services.Helpers;
88

99
namespace Refactoring.Web.Controllers {
10+
1011
public class HomeController : Controller {
1112
private readonly ILogger<HomeController> _logger;
1213

1314
public HomeController(ILogger<HomeController> logger) {
1415
_logger = logger;
1516
}
16-
17+
1718
public IActionResult Index() {
1819
_logger.LogDebug("Index loaded");
19-
var districts = new List<string> {
20-
"Cambridge", "Downtown", "County", "Middleton"
21-
};
2220
var viewModel = new OrderFormModel {
23-
Districts = districts.Select(d => new SelectListItem {
21+
Districts = District.StandardDistricts.Select(
22+
d => new SelectListItem {
2423
Value = d.ToLower(),
2524
Text = d
2625
})
Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
using System.Threading.Tasks;
22
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.Extensions.Logging;
34
using Refactoring.Web.DomainModels;
4-
using Refactoring.Web.Services;
5+
using Refactoring.Web.Services.Interfaces;
56

67
namespace Refactoring.Web.Controllers {
78
public class OrderController : Controller {
9+
private readonly ILogger<OrderController> _logger;
10+
private readonly IOrderService _orderService;
11+
12+
public OrderController(
13+
ILogger<OrderController> logger,
14+
IOrderService orderService) {
15+
_logger = logger;
16+
_orderService = orderService;
17+
}
18+
819
public IActionResult Index() {
920
return View();
1021
}
1122

1223
[HttpPost]
1324
public async Task<IActionResult> SubmitOrder(string selectedDistrict, decimal orderAmount) {
14-
var order = new Order();
15-
order.District = selectedDistrict;
16-
order.Total = orderAmount;
17-
var orderService = new OrderService(order);
18-
await orderService.ProcessOrder();
19-
var completedOrder = orderService.GetOrder();
20-
return View(completedOrder);
25+
var order = new Order {
26+
District = selectedDistrict,
27+
Total = orderAmount
28+
};
29+
30+
order = await _orderService.ProcessOrder(order);
31+
32+
if (order != null) {
33+
_logger.LogDebug($"Processed Order: {order.Id}");
34+
return View(order);
35+
}
36+
37+
_logger.LogError("Error processing order");
38+
return StatusCode(500);
2139
}
2240
}
2341
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=6c751723_002D4e57_002D4952_002D80ca_002Dbbfc25aa7958/@EntryIndexedValue">&lt;SessionState ContinuousTestingIsOn="False" ContinuousTestingMode="0" FrameworkVersion="{x:Null}" IsLocked="False" Name="GivenDateIsTuesday_ImageUrl_Set_OnOrderAdvert" PlatformMonoPreference="{x:Null}" PlatformType="{x:Null}" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
3+
&lt;TestAncestor&gt;
4+
&lt;TestId&gt;xUnit::379BF7AF-7FEB-25F1-4786-CB2C870A3E27::.NETCoreApp,Version=v3.1::Refactoring.Web.Tests.OrderProcessors.TestCambridgeOrderProcessor.GivenDateIsTuesday_ImageUrl_Set_OnOrderAdvert&lt;/TestId&gt;
5+
&lt;/TestAncestor&gt;
6+
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>

Refactoring.Web/Refactoring.Web.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
<ItemGroup>
1919
<PackageReference Include="AWSSDK.SQS" Version="3.5.0.24" />
20+
<PackageReference Include="FluentAssertions" Version="5.10.3" />
2021
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
2122
</ItemGroup>
2223

Refactoring.Web/Services/ChamberOfCommerceAPI.cs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
1-
using System.Collections.Generic;
1+
using System;
22
using System.Net.Http;
33
using System.Threading.Tasks;
4+
using Microsoft.Extensions.Configuration;
45
using Newtonsoft.Json;
6+
using Refactoring.Web.Services.Helpers;
7+
using Refactoring.Web.Services.Interfaces;
58

69
namespace Refactoring.Web.Services {
7-
public static class ChamberOfCommerceApi {
8-
public static async Task<DataResult> GetFor(string district) {
9-
var client = new HttpClient();
10-
var districtLookup = new Dictionary<string, int>() {
11-
{"downtown", 11},
12-
{"county", 23},
13-
{"middleton", 18},
14-
{"cambridge", 42}
15-
};
16-
var request = new HttpRequestMessage(HttpMethod.Get,
17-
$"https://jsonplaceholder.typicode.com/photos/{districtLookup[district.ToLower()].ToString()}");
10+
public class ChamberOfCommerceApi : IChamberOfCommerceApi {
11+
private readonly IConfiguration _config;
12+
13+
public ChamberOfCommerceApi(IConfiguration config) {
14+
_config = config;
15+
}
16+
17+
/// <summary>
18+
/// For the provided `district` returns the `DataResult` object containing
19+
/// the id, thumbnail url, and title for the district's image
20+
/// </summary>
21+
/// <param name="district"></param>
22+
/// <returns></returns>
23+
public async Task<DataResult> GetImageAndThumbnailDataFor(string district) {
24+
using var client = new HttpClient();
25+
var absoluteUrl = BuildUrlForDistrict(district);
26+
var request = new HttpRequestMessage(HttpMethod.Get, absoluteUrl);
1827
var response = client.SendAsync(request);
1928
var data = await response.Result.Content.ReadAsStringAsync();
2029
var result = JsonConvert.DeserializeObject<DataResult>(data);
2130
return result;
2231
}
32+
33+
private Uri BuildUrlForDistrict(string district) {
34+
var districtId = District.GetDistrictNumberByName(district);
35+
var basePhotoUrl = new Uri(_config.GetValue<string>("BasePhotoUrl"));
36+
return new Uri(basePhotoUrl, districtId.ToString());
37+
}
2338
}
2439

2540
public struct DataResult {
Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,16 @@
11
using System;
2-
using System.Collections.Generic;
2+
using Refactoring.Web.Services.Interfaces;
33

44
namespace Refactoring.Web.Services {
5-
public class DealService {
6-
public DealService() { }
7-
8-
public decimal GenerateDeal(DateTime dateTime) {
9-
if (dateTime.Hour > 12 && dateTime.Hour < 24) {
10-
return 0.1M;
11-
} else {
12-
return 0.05M;
13-
}
14-
}
5+
public class DealService : IDealService {
6+
public static decimal PmRate => 0.1M;
7+
public static decimal AmRate => 0.05M;
158

16-
public string GetRandomLocalBusiness() {
17-
var lbs = new List<string> {
18-
"Barbershop", "Bakery", "Shoe Store", "Pizza Place", "Diner", "Auto Repair", "Pharmacy", "Grocery", "Bakery"
19-
};
20-
var random = new Random();
21-
var idx = random.Next(lbs.Count);
22-
return lbs[idx];
23-
}
9+
public decimal GenerateDeal(DateTime dateTime)
10+
=> IsAfternoon(dateTime) ? PmRate : AmRate;
11+
12+
private static bool IsAfternoon(DateTime dateTime)
13+
=> dateTime.Hour > 12
14+
&& dateTime.Hour < 24;
2415
}
2516
}

0 commit comments

Comments
 (0)