diff --git a/.gitignore b/.gitignore index b335d4e..fa989d3 100644 --- a/.gitignore +++ b/.gitignore @@ -245,6 +245,5 @@ ModelManifest.xml .fake/ /src/.idea -tests/ .vscode/ .idea/ \ No newline at end of file diff --git a/Chapter13/Marketplace.sln b/Chapter13/Marketplace.sln index b725549..2ab4579 100644 --- a/Chapter13/Marketplace.sln +++ b/Chapter13/Marketplace.sln @@ -4,8 +4,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace", "src\Marketpl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace.Ads.Domain", "src\Marketplace.Ads.Domain\Marketplace.Ads.Domain.csproj", "{AD477131-DFD9-4CF1-A42F-7B932148B4AD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace.Ads.Tests", "tests\Marketplace.Ads.Tests\Marketplace.Ads.Tests.csproj", "{F682B8F9-A43B-4D6D-BECE-4F45767A026A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace.EventSourcing", "src\Marketplace.EventSourcing\Marketplace.EventSourcing.csproj", "{FEE71FF8-559C-40CC-9AF5-1E4051EE9C7C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace.PaidServices.Domain", "src\Marketplace.PaidServices.Domain\Marketplace.PaidServices.Domain.csproj", "{5B72EA27-0DE0-45C9-80C1-17A3F30DB6E5}" @@ -34,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace.Users.Messages" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace.WebApi", "src\Marketplace.WebApi\Marketplace.WebApi.csproj", "{2ED6B97C-4C4B-4A35-8CF3-57B3BD8F8D2B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marketplace.Ads.Tests", "tests\Marketplace.Ads.Tests\Marketplace.Ads.Tests.csproj", "{513B7F24-8DB2-4D18-AF8E-3707F4D75E5C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -48,10 +48,6 @@ Global {AD477131-DFD9-4CF1-A42F-7B932148B4AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD477131-DFD9-4CF1-A42F-7B932148B4AD}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD477131-DFD9-4CF1-A42F-7B932148B4AD}.Release|Any CPU.Build.0 = Release|Any CPU - {F682B8F9-A43B-4D6D-BECE-4F45767A026A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F682B8F9-A43B-4D6D-BECE-4F45767A026A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F682B8F9-A43B-4D6D-BECE-4F45767A026A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F682B8F9-A43B-4D6D-BECE-4F45767A026A}.Release|Any CPU.Build.0 = Release|Any CPU {FEE71FF8-559C-40CC-9AF5-1E4051EE9C7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FEE71FF8-559C-40CC-9AF5-1E4051EE9C7C}.Debug|Any CPU.Build.0 = Debug|Any CPU {FEE71FF8-559C-40CC-9AF5-1E4051EE9C7C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -100,12 +96,16 @@ Global {2ED6B97C-4C4B-4A35-8CF3-57B3BD8F8D2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {2ED6B97C-4C4B-4A35-8CF3-57B3BD8F8D2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {2ED6B97C-4C4B-4A35-8CF3-57B3BD8F8D2B}.Release|Any CPU.Build.0 = Release|Any CPU + {513B7F24-8DB2-4D18-AF8E-3707F4D75E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {513B7F24-8DB2-4D18-AF8E-3707F4D75E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {513B7F24-8DB2-4D18-AF8E-3707F4D75E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {513B7F24-8DB2-4D18-AF8E-3707F4D75E5C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution - {F682B8F9-A43B-4D6D-BECE-4F45767A026A} = {11ACA044-780C-4C71-A6F7-ECFB6B26B9E7} {FEE71FF8-559C-40CC-9AF5-1E4051EE9C7C} = {B8B2A008-6E95-4BEE-9BE3-DC621B4DC4EC} {EA7B5B15-9095-4082-ADC3-E367513C54B6} = {B8B2A008-6E95-4BEE-9BE3-DC621B4DC4EC} {D2D334CA-B388-47EB-848A-4345A4E0E221} = {B8B2A008-6E95-4BEE-9BE3-DC621B4DC4EC} {2ED6B97C-4C4B-4A35-8CF3-57B3BD8F8D2B} = {B8B2A008-6E95-4BEE-9BE3-DC621B4DC4EC} + {513B7F24-8DB2-4D18-AF8E-3707F4D75E5C} = {11ACA044-780C-4C71-A6F7-ECFB6B26B9E7} EndGlobalSection EndGlobal diff --git a/Chapter13/src/Marketplace.Users/Marketplace.Users.csproj b/Chapter13/src/Marketplace.Users/Marketplace.Users.csproj index 221e89c..8d9600c 100644 --- a/Chapter13/src/Marketplace.Users/Marketplace.Users.csproj +++ b/Chapter13/src/Marketplace.Users/Marketplace.Users.csproj @@ -6,6 +6,7 @@ + diff --git a/Chapter13/tests/Marketplace.Ads.Tests/ClassifiedAd_Publish_Spec.cs b/Chapter13/tests/Marketplace.Ads.Tests/ClassifiedAd_Publish_Spec.cs new file mode 100644 index 0000000..232d12f --- /dev/null +++ b/Chapter13/tests/Marketplace.Ads.Tests/ClassifiedAd_Publish_Spec.cs @@ -0,0 +1,101 @@ +using System; +using Marketplace.Ads.Domain.ClassifiedAds; +using Marketplace.Ads.Domain.Shared; +using Xunit; + +namespace Marketplace.ClassifiedAds.Tests +{ + public class ClassifiedAd_Publish_Spec + { + public ClassifiedAd_Publish_Spec() + => Ad = ClassifiedAd.Create( + ClassifiedAdId.FromGuid(Guid.NewGuid()), + UserId.FromGuid(Guid.NewGuid()) + ); + + ClassifiedAd Ad { get; } + + [Fact] + public void Can_publish_a_valid_ad() + { + Ad.SetTitle(ClassifiedAdTitle.FromString("Test ad")); + + Ad.UpdateText( + ClassifiedAdText.FromString("Please buy my stuff") + ); + + Ad.UpdatePrice( + Price.FromDecimal(100.10m, "EUR", new FakeCurrencyLookup()) + ); + + Ad.RequestToPublish(); + + Assert.Equal( + ClassifiedAd.ClassifiedAdState.PendingReview, + Ad.State + ); + } + + [Fact] + public void Cannot_publish_with_zero_price() + { + Ad.SetTitle(ClassifiedAdTitle.FromString("Test ad")); + + Ad.UpdateText( + ClassifiedAdText.FromString("Please buy my stuff") + ); + + Ad.UpdatePrice( + Price.FromDecimal(0.0m, "EUR", new FakeCurrencyLookup()) + ); + + Assert.Throws( + () => Ad.RequestToPublish() + ); + } + + [Fact] + public void Cannot_publish_without_price() + { + Ad.SetTitle(ClassifiedAdTitle.FromString("Test ad")); + + Ad.UpdateText( + ClassifiedAdText.FromString("Please buy my stuff") + ); + + Assert.Throws( + () => Ad.RequestToPublish() + ); + } + + [Fact] + public void Cannot_publish_without_text() + { + Ad.SetTitle(ClassifiedAdTitle.FromString("Test ad")); + + Ad.UpdatePrice( + Price.FromDecimal(100.10m, "EUR", new FakeCurrencyLookup()) + ); + + Assert.Throws( + () => Ad.RequestToPublish() + ); + } + + [Fact] + public void Cannot_publish_without_title() + { + Ad.UpdateText( + ClassifiedAdText.FromString("Please buy my stuff") + ); + + Ad.UpdatePrice( + Price.FromDecimal(100.10m, "EUR", new FakeCurrencyLookup()) + ); + + Assert.Throws( + () => Ad.RequestToPublish() + ); + } + } +} \ No newline at end of file diff --git a/Chapter13/tests/Marketplace.Ads.Tests/FakeCurrencyLookup.cs b/Chapter13/tests/Marketplace.Ads.Tests/FakeCurrencyLookup.cs new file mode 100644 index 0000000..6708ced --- /dev/null +++ b/Chapter13/tests/Marketplace.Ads.Tests/FakeCurrencyLookup.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Linq; +using Marketplace.Ads.Domain.Shared; + +namespace Marketplace.ClassifiedAds.Tests +{ + public class FakeCurrencyLookup : ICurrencyLookup + { + static readonly IEnumerable _currencies = + new[] + { + new Currency + { + CurrencyCode = "EUR", + DecimalPlaces = 2, + InUse = true + }, + new Currency + { + CurrencyCode = "USD", + DecimalPlaces = 2, + InUse = true + }, + new Currency + { + CurrencyCode = "JPY", + DecimalPlaces = 0, + InUse = true + }, + new Currency + { + CurrencyCode = "DEM", + DecimalPlaces = 2, + InUse = false + } + }; + + public Currency FindCurrency(string currencyCode) + { + var currency = _currencies.FirstOrDefault(x => x.CurrencyCode == currencyCode); + return currency ?? Currency.None; + } + } +} \ No newline at end of file diff --git a/Chapter13/tests/Marketplace.Ads.Tests/Marketplace.Ads.Tests.csproj b/Chapter13/tests/Marketplace.Ads.Tests/Marketplace.Ads.Tests.csproj new file mode 100644 index 0000000..68bdf67 --- /dev/null +++ b/Chapter13/tests/Marketplace.Ads.Tests/Marketplace.Ads.Tests.csproj @@ -0,0 +1,18 @@ + + + netcoreapp2.2 + latest + false + Marketplace.ClassifiedAds.Tests + + + + + + + + + + + + \ No newline at end of file diff --git a/Chapter13/tests/Marketplace.Ads.Tests/Money_Spec.cs b/Chapter13/tests/Marketplace.Ads.Tests/Money_Spec.cs new file mode 100644 index 0000000..8d90242 --- /dev/null +++ b/Chapter13/tests/Marketplace.Ads.Tests/Money_Spec.cs @@ -0,0 +1,96 @@ +using System; +using Marketplace.Ads.Domain.Shared; +using Xunit; + +namespace Marketplace.ClassifiedAds.Tests +{ + public class Money_Spec + { + static readonly ICurrencyLookup CurrencyLookup = + new FakeCurrencyLookup(); + + [Fact] + public void FromString_and_FromDecimal_should_be_equal() + { + var firstAmount = Money.FromDecimal(5, "EUR", CurrencyLookup); + var secondAmount = Money.FromString("5.00", "EUR", CurrencyLookup); + + Assert.Equal(firstAmount, secondAmount); + } + + [Fact] + public void Sum_of_money_gives_full_amount() + { + var coin1 = Money.FromDecimal(1, "EUR", CurrencyLookup); + var coin2 = Money.FromDecimal(2, "EUR", CurrencyLookup); + var coin3 = Money.FromDecimal(2, "EUR", CurrencyLookup); + + var banknote = Money.FromDecimal(5, "EUR", CurrencyLookup); + + Assert.Equal(banknote, coin1 + coin2 + coin3); + } + + [Fact] + public void Throw_when_too_many_decimal_places() + => Assert.Throws( + () => + Money.FromDecimal(100.123m, "EUR", CurrencyLookup) + ); + + [Fact] + public void Throws_on_adding_different_currencies() + { + var firstAmount = Money.FromDecimal(5, "USD", CurrencyLookup); + var secondAmount = Money.FromDecimal(5, "EUR", CurrencyLookup); + + Assert.Throws( + () => + firstAmount + secondAmount + ); + } + + [Fact] + public void Throws_on_substracting_different_currencies() + { + var firstAmount = Money.FromDecimal(5, "USD", CurrencyLookup); + var secondAmount = Money.FromDecimal(5, "EUR", CurrencyLookup); + + Assert.Throws( + () => + firstAmount - secondAmount + ); + } + + [Fact] + public void Two_of_same_amount_but_different_Currencies_should_not_be_equal() + { + var firstAmount = Money.FromDecimal(5, "EUR", CurrencyLookup); + var secondAmount = Money.FromDecimal(5, "USD", CurrencyLookup); + + Assert.NotEqual(firstAmount, secondAmount); + } + + [Fact] + public void Two_of_same_amount_should_be_equal() + { + var firstAmount = Money.FromDecimal(5, "EUR", CurrencyLookup); + var secondAmount = Money.FromDecimal(5, "EUR", CurrencyLookup); + + Assert.Equal(firstAmount, secondAmount); + } + + [Fact] + public void Unknown_currency_should_not_be_allowed() + => Assert.Throws( + () => + Money.FromDecimal(100, "WHAT?", CurrencyLookup) + ); + + [Fact] + public void Unused_currency_should_not_be_allowed() + => Assert.Throws( + () => + Money.FromDecimal(100, "DEM", CurrencyLookup) + ); + } +} \ No newline at end of file