diff --git a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj index b537fc2..dbb2f7b 100644 --- a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj +++ b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj @@ -1,16 +1,28 @@ - - + + + + + + Debug AnyCPU - cd5d577e-bdc9-4dfc-ac6a-b1da474995f3 + {60CFE149-CB3F-4227-8EAD-4E16C0796535} Library Properties AnyCompany.Tests AnyCompany.Tests - v4.6.1 + v4.7.2 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + true @@ -30,24 +42,176 @@ 4 - - - - - - - - - - - - - - + + ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Bcl.HashCode.1.1.0\lib\net461\Microsoft.Bcl.HashCode.dll + + + ..\packages\Microsoft.Data.Sqlite.Core.3.1.6\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + + + ..\packages\Microsoft.DotNet.PlatformAbstractions.3.1.6\lib\net45\Microsoft.DotNet.PlatformAbstractions.dll + + + ..\packages\Microsoft.EntityFrameworkCore.3.1.6\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll + + + ..\packages\Microsoft.EntityFrameworkCore.InMemory.3.1.6\lib\netstandard2.0\Microsoft.EntityFrameworkCore.InMemory.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Relational.3.1.6\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.3.1.6\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Memory.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll + + + ..\packages\Microsoft.Extensions.Configuration.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Configuration.Binder.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.3.1.6\lib\net461\Microsoft.Extensions.DependencyInjection.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.DependencyModel.3.1.6\lib\net451\Microsoft.Extensions.DependencyModel.dll + + + ..\packages\Microsoft.Extensions.Logging.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Logging.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Options.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Primitives.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + + + ..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + + + ..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + ..\packages\Moq.4.14.5\lib\net45\Moq.dll + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll + + + ..\packages\SQLitePCLRaw.bundle_e_sqlite3.2.0.2\lib\net461\SQLitePCLRaw.batteries_v2.dll + + + ..\packages\SQLitePCLRaw.core.2.0.2\lib\netstandard2.0\SQLitePCLRaw.core.dll + + + ..\packages\SQLitePCLRaw.bundle_e_sqlite3.2.0.2\lib\net461\SQLitePCLRaw.nativelibrary.dll + + + ..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.2\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll + + + ..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll + + + + + + + ..\packages\System.Diagnostics.DiagnosticSource.4.7.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + - + + + + + + + + + + + + + {E882A9A5-1265-4E61-9BBC-9A50989BA147} + AnyCompany + + + + - + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + \ No newline at end of file diff --git a/TechTest/AnyCompany.Tests/Class1.cs b/TechTest/AnyCompany.Tests/Class1.cs deleted file mode 100644 index 5957505..0000000 --- a/TechTest/AnyCompany.Tests/Class1.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AnyCompany.Tests -{ - public class Class1 - { - } -} diff --git a/TechTest/AnyCompany.Tests/MockData/InMemoryAnyCompanyContext.cs b/TechTest/AnyCompany.Tests/MockData/InMemoryAnyCompanyContext.cs new file mode 100644 index 0000000..8a21510 --- /dev/null +++ b/TechTest/AnyCompany.Tests/MockData/InMemoryAnyCompanyContext.cs @@ -0,0 +1,14 @@ + +namespace InvestecUnitTestsTests.MockData +{ + using AnyCompany; + using AnyCompany.DAL; + using Microsoft.EntityFrameworkCore; + public class RepoAnyCompanyContext : AnyCompanyContext + { + public RepoAnyCompanyContext(DbContextOptions option) : base() + { + + } + } +} \ No newline at end of file diff --git a/TechTest/AnyCompany.Tests/Properties/AssemblyInfo.cs b/TechTest/AnyCompany.Tests/Properties/AssemblyInfo.cs index 726eefa..c2e3ab8 100644 --- a/TechTest/AnyCompany.Tests/Properties/AssemblyInfo.cs +++ b/TechTest/AnyCompany.Tests/Properties/AssemblyInfo.cs @@ -1,36 +1,20 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("AnyCompany.Tests")] +[assembly: AssemblyTitle("InvestecUnitTests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Investec Bank")] -[assembly: AssemblyProduct("AnyCompany.Tests")] -[assembly: AssemblyCopyright("Copyright © Investec Bank 2018")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("InvestecUnitTests")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("cd5d577e-bdc9-4dfc-ac6a-b1da474995f3")] +[assembly: Guid("60cfe149-cb3f-4227-8ead-4e16c0796535")] -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TechTest/AnyCompany.Tests/RepositoryTests/CustomerRepositoryTests.cs b/TechTest/AnyCompany.Tests/RepositoryTests/CustomerRepositoryTests.cs new file mode 100644 index 0000000..40ec0b2 --- /dev/null +++ b/TechTest/AnyCompany.Tests/RepositoryTests/CustomerRepositoryTests.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data.Common; +using System.Data.Entity.Migrations; +using System.Linq; +using AnyCompany; +using AnyCompany.BUL.Services; +using AnyCompany.DAL; +using AnyCompany.DAL.Repositories; +using InvestecUnitTestsTests.MockData; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Moq; +using NUnit.Framework; + +namespace InvestecUnitTests +{ + [TestFixture] + public class CustomerRepositoryTests : TestsBase + { + [TestCase] + public void GIVEN_VALID_CUSTOMERID_RETURN_CUSTOMER() + { + //Arrange + Customer returnedCustomer = null; + int customerIdToGet = 1; + + Customers.ToList().ForEach(i => RepoContext.Customers.AddOrUpdate(i)); + RepoContext.SaveChanges(); + + //Act + CustomerRepositoryWrapper CustomerWrapper = new CustomerRepositoryWrapper(); + returnedCustomer = CustomerWrapper.Get(customerIdToGet); + + //Assert + Assert.True(returnedCustomer != null); + Assert.True(returnedCustomer.CustomerId == customerIdToGet); + } + + + [TestCase] + public void GIVEN_NONEXISTENT_CUSTOMERID_RETURN_NULL() + { + //Arrange + Customer returnedCustomer = null; + int customerIdToGet = -9999; + + Customers.ToList().ForEach(i => RepoContext.Customers.AddOrUpdate(i)); + RepoContext.SaveChanges(); + + //Act + CustomerRepositoryWrapper CustomerWrapper = new CustomerRepositoryWrapper(); + returnedCustomer = CustomerWrapper.Get(customerIdToGet); + + //Assert + Assert.True(returnedCustomer == null); + } + + [TestCase] + public void RETURN_CUSTOMERS_WITH_LINKED_ORDERS_BY_DEFAULT() + { + //Arrange + CustomersWithOrders.ToList().ForEach(i => RepoContext.Customers.AddOrUpdate(i)); + RepoContext.SaveChanges(); + + //Act + CustomerRepositoryWrapper customerWrapper = new CustomerRepositoryWrapper(); + IEnumerable returnedCustomers = customerWrapper.GetAll(); + int orderCount = 0; + returnedCustomers.ToList().ForEach(customer => orderCount += customer.Orders.Count); + + //Assert + Assert.True(orderCount > 0); + Assert.True(returnedCustomers.Count() > 0); + } + + [TestCase] + public void GIVEN_FALSE_ARGUMENT_RETURN_CUSTOMERS_WITHOUT_LINKED_ORDERS() + { + //Arrange + CustomersWithOrders.ToList().ForEach(i => RepoContext.Customers.AddOrUpdate(i)); + RepoContext.SaveChanges(); + + //Act + CustomerRepositoryWrapper customerWrapper = new CustomerRepositoryWrapper(); + IEnumerable returnedCustomers = customerWrapper.GetAll(false); + int orderCount = 0; + returnedCustomers.ToList().ForEach(customer => orderCount += customer.Orders.Count); + + //Assert + Assert.True(orderCount == 0); + Assert.True(returnedCustomers.Count() > 0); + } + } +} diff --git a/TechTest/AnyCompany.Tests/RepositoryTests/OrderRepositoryTests.cs b/TechTest/AnyCompany.Tests/RepositoryTests/OrderRepositoryTests.cs new file mode 100644 index 0000000..ef4e946 --- /dev/null +++ b/TechTest/AnyCompany.Tests/RepositoryTests/OrderRepositoryTests.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data.Common; +using System.Linq; +using AnyCompany; +using AnyCompany.BUL.Services; +using AnyCompany.DAL; +using AnyCompany.DAL.Repositories; +using InvestecUnitTestsTests.MockData; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Moq; +using NUnit.Framework; + +namespace InvestecUnitTests +{ + [TestFixture] + public class OrderRepositoryTests : TestsBase + { + [TestCase] + public void GIVEN_VALID_ORDER_RETURN_TRUE() + { + //Arrange + + //Act + OrderRepositoryWrapper orderWrapper = new OrderRepositoryWrapper(); + bool isSaved = orderWrapper.Save(ValidOrder); + + //Assert + Assert.True(isSaved == true); + } + + + [TestCase] + public void GIVEN_INVALID_ORDER_RETURN_FALSE() + { + //Arrange + + //Act + OrderRepositoryWrapper orderWrapper = new OrderRepositoryWrapper(); + bool isSaved = orderWrapper.Save(InValidOrder); + + //Assert + Assert.True(isSaved == false); + } + } +} diff --git a/TechTest/AnyCompany.Tests/ServiceTests/CustomerServiceTests.cs b/TechTest/AnyCompany.Tests/ServiceTests/CustomerServiceTests.cs new file mode 100644 index 0000000..9f99ce1 --- /dev/null +++ b/TechTest/AnyCompany.Tests/ServiceTests/CustomerServiceTests.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AnyCompany; +using AnyCompany.BUL.Helpers; +using AnyCompany.BUL.Services; +using AnyCompany.DAL; +using AnyCompany.DAL.Repositories; +using Moq; +using NUnit.Framework; + +namespace InvestecUnitTests +{ + [TestFixture] + public class CustomerServiceTests + { + private Mock _customerService = new Mock(); + private CustomerService customerService; + private readonly List customers = new List + { + new Customer + { + Name = "Mike America", Country = "US", DateOfBirth = DateTime.Parse("1987-06-01"), CustomerId = 1 + }, + new Customer + { + Name = "Jonathan Canada", Country = "CN", DateOfBirth = DateTime.Parse("1925-06-01"), CustomerId = 2 + }, + new Customer + { + Name = "FROM THE UK CHINKU", Country = "UK", DateOfBirth = DateTime.Parse("2001-06-01"), CustomerId = 3 + } + , + new Customer + { + Name = "Not in Database Adams", Country = "AG", DateOfBirth = DateTime.Parse("1982-12-12"), CustomerId = 50 + } + }; + private readonly List customersWithOrders = new List + { + new Customer + { + Name = "I Have Order too", Country = "NM", DateOfBirth = DateTime.Parse("1987-06-01"), CustomerId = 12 + , Orders = new List() + { + new Order + { + Amount = 500, + OrderId = 12, + CustomerId = 1, + VAT = 15 + } + } + }, + new Customer + { + Name = "I Have Order", Country = "ZW", DateOfBirth = DateTime.Parse("1925-06-01"), CustomerId = 13 + , Orders = new List() + { + new Order + { + Amount = 500, + OrderId = 12, + CustomerId = 1, + VAT = 15 + } + } + } + }; + + [TestCase] + public void GIVEN_EXISTINGId_RETURNS_MATCHING_CUSTOMER() + { + //Arrange + Customer matchingCustomer = customers[2]; + _customerService.Setup(x => x.Get(matchingCustomer.CustomerId)).Returns(matchingCustomer); + + //Act + customerService = new CustomerService(_customerService.Object); + Customer returnedCustomer = customerService.RetrieveACustomer(matchingCustomer.CustomerId); + + //Asset + Assert.AreSame(returnedCustomer, matchingCustomer); + Assert.AreEqual(returnedCustomer.CustomerId, matchingCustomer.CustomerId); + } + + [TestCase] + public void GIVEN_WRONGId_RETURNS_NONMATCHING_CUSTOMER() + { + //Arrange + Customer customerToGet = customers[2]; + Customer notMatchingCustomer = customers[0]; + _customerService.Setup(x => x.Get(customerToGet.CustomerId)).Returns(notMatchingCustomer); + + //Act + customerService = new CustomerService(_customerService.Object); + Customer returnedCustomer = customerService.RetrieveACustomer(customerToGet.CustomerId); + + //Asset + Assert.AreNotSame(returnedCustomer, customerToGet); + } + + [TestCase] + public void GIVEN_NONEXISTENTId_RETURNS_EMPTYCUSTOMEROBJECT() + { + //Arrange + int NonExtentId = 344; + + _customerService.Setup(x => x.Get(NonExtentId)).Returns(new Customer()); + + //Act + customerService = new CustomerService(_customerService.Object); + Customer returnedCustomer = customerService.RetrieveACustomer(NonExtentId); + + //Asset + Assert.True(returnedCustomer.CustomerId == 0); + } + + [TestCase] + public void GIVEN_TRUE_ARGUMENT_RETURNS_CUSTOMERS_WITH_LINKED_ORDERS() + { + //Arrange + _customerService.Setup(x => x.GetAll(true)).Returns(customersWithOrders); + + //Act + customerService = new CustomerService(_customerService.Object); + IEnumerable returnedCustomers = customerService.RetrieveCustomers(true); + int orderCount = 0; + returnedCustomers.ToList().ForEach(i => orderCount += i.Orders.Count); + + //Asset + Assert.AreSame(customersWithOrders, returnedCustomers); + Assert.True(orderCount > 0); + } + + [TestCase] + public void GIVEN_FALSE_ARGUMENT_RETURNS_CUSTOMERS_WITHOUT_LINKED_ORDERS() + { + //Arrange + _customerService.Setup(x => x.GetAll(false)).Returns(customers); + + //Act + customerService = new CustomerService(_customerService.Object); + IEnumerable returnedCustomers = customerService.RetrieveCustomers(false); + + int orderCount = 0; + returnedCustomers.ToList().ForEach(customer => orderCount += customer.Orders.Count); + + //Asset + Assert.AreEqual(orderCount, 0); + Assert.AreNotSame(returnedCustomers, customersWithOrders); + } + } +} diff --git a/TechTest/AnyCompany.Tests/ServiceTests/OrderServiceTests.cs b/TechTest/AnyCompany.Tests/ServiceTests/OrderServiceTests.cs new file mode 100644 index 0000000..64efe3a --- /dev/null +++ b/TechTest/AnyCompany.Tests/ServiceTests/OrderServiceTests.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using AnyCompany; +using AnyCompany.BUL.Services; +using AnyCompany.DAL; +using Moq; +using NUnit.Framework; + +namespace InvestecUnitTests +{ + [TestFixture] + public class OrderServiceTests + { + private Mock _orderService = new Mock(); + private Mock _customerService = new Mock(); + private OrderService orderService; + private List customers = new List + { + new Customer + { + Name = "Mike America", Country = "US", DateOfBirth = DateTime.Parse("1987-06-01"), CustomerId = 1 + }, + new Customer + { + Name = "Jonathan Canada", Country = "CN", DateOfBirth = DateTime.Parse("1925-06-01"), CustomerId = 2 + }, + new Customer + { + Name = "FROM THE UK CHINKU", Country = "UK", DateOfBirth = DateTime.Parse("2001-06-01"), CustomerId = 3 + } + , + new Customer + { + Name = "Not in Database Adams", Country = "AG", DateOfBirth = DateTime.Parse("1982-12-12"), CustomerId = 50 + } + }; + private readonly Order validOrder = new Order + { + Amount = 500, + CustomerId = 1, + VAT = 50 + }; + private readonly Order invalidOrder = new Order + { + Amount = -89, + VAT = 50 + }; + + [TestCase] + public void GIVEN_VALIDORDER_RETURNS_TRUE() + { + //Arrange + Customer NonUKCustomer = customers[0]; + validOrder.CustomerId = NonUKCustomer.CustomerId; + _orderService.Setup(x => x.Save(validOrder)).Returns(true); + _customerService.Setup(x => x.Get(validOrder.CustomerId)).Returns(NonUKCustomer); + + //Act + orderService = new OrderService(_orderService.Object,_customerService.Object); + bool orderResult = orderService.PlaceOrder(validOrder, validOrder.CustomerId); + + //Asset + Assert.AreEqual(orderResult, true); + } + + [TestCase] + public void GIVEN_INVALIDORDERAMOUNT_RETURNS_FALSE() + { + //Arrange + Customer NonUKCustomer = customers[0]; + validOrder.CustomerId = NonUKCustomer.CustomerId; + _orderService.Setup(x => x.Save(invalidOrder)).Returns(false); + + //Act + orderService = new OrderService(_orderService.Object, _customerService.Object); + bool orderResult = orderService.PlaceOrder(validOrder, validOrder.CustomerId); + + //Asset + Assert.AreEqual(orderResult, false); + } + + [TestCase] + public void GIVEN_UKCUSTOMER_APPLIES_CORRECT_VAT_AMOUNT_RETURNS_TRUE() + { + //Arrange + Customer UKcustomer = customers[2]; + validOrder.CustomerId = UKcustomer.CustomerId; + _orderService.Setup(x => x.Save(validOrder)).Returns(true); + _customerService.Setup(x => x.Get(validOrder.CustomerId)).Returns(UKcustomer); + + //Act + orderService = new OrderService(_orderService.Object, _customerService.Object); + bool orderResult = orderService.PlaceOrder(validOrder, validOrder.CustomerId); + + //Asset + Assert.AreEqual(orderResult, true); + } + } +} diff --git a/TechTest/AnyCompany.Tests/TestsBase.cs b/TechTest/AnyCompany.Tests/TestsBase.cs new file mode 100644 index 0000000..bf59b13 --- /dev/null +++ b/TechTest/AnyCompany.Tests/TestsBase.cs @@ -0,0 +1,115 @@ +//using Microsoft.EntityFrameworkCore; + +using AnyCompany; +using InvestecUnitTestsTests.MockData; +using AnyCompany.DAL; +using Moq; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; + +namespace InvestecUnitTests +{ + public class TestsBase + { + public RepoAnyCompanyContext RepoContext = RepositoryDataContext(); + public List Customers = new List + { + new Customer + { + Name = "Mike America", Country = "US", DateOfBirth = DateTime.Parse("1987-06-01"), CustomerId = 1 + }, + new Customer + { + Name = "Jonathan Canada", Country = "CN", DateOfBirth = DateTime.Parse("1925-06-01"), CustomerId = 2 + }, + new Customer + { + Name = "FROM THE UK CHINKU", Country = "UK", DateOfBirth = DateTime.Parse("2001-06-01"), CustomerId = 3 + } + , + new Customer + { + Name = "Not in Database Adams", Country = "AG", DateOfBirth = DateTime.Parse("1982-12-12"), CustomerId = 50 + } + , + new Customer + { + Name = "Malawi James", Country = "MW", DateOfBirth = DateTime.Parse("1989-02-06"), CustomerId = 4 + } + }; + public List CustomersWithOrders = new List + { + new Customer + { + Name = "I Have 1 Order", Country = "NM", DateOfBirth = DateTime.Parse("1987-06-01"), CustomerId = 12 + , Orders = new List() + { + new Order + { + Amount = 500, + OrderId = 12, + CustomerId = 12, + VAT = 15 + } + } + }, + new Customer + { + Name = "I Have 2 Orders", Country = "ZW", DateOfBirth = DateTime.Parse("1925-06-01"), CustomerId = 13 + , Orders = new List() + { + new Order + { + Amount = 500, + OrderId = 12, + CustomerId = 13, + VAT = 15 + } + + , + new Order + { + Amount = -650, + OrderId = 13, + CustomerId = 13, + VAT = 5 + } + } + + } + }; + public Order ValidOrder = new Order + { + Amount = 8700, + CustomerId = 1, + VAT = 2, + }; + + public Order InValidOrder = new Order + { + Amount = -10, + CustomerId = 2502, + VAT = 3, + }; + private static RepoAnyCompanyContext RepositoryDataContext() + { + return new RepoAnyCompanyContext(new DbContextOptionsBuilder() + .UseSqlite("DataSource:inMemory:") + .Options); + } + + [SetUp] + public void Setup() + { + + } + + [TearDown] + protected void DisposeDatabase() + { + // RepoContext.Dispose(); + } + } +} \ No newline at end of file diff --git a/TechTest/AnyCompany.Tests/app.config b/TechTest/AnyCompany.Tests/app.config new file mode 100644 index 0000000..47cd2b7 --- /dev/null +++ b/TechTest/AnyCompany.Tests/app.config @@ -0,0 +1,79 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TechTest/AnyCompany.Tests/packages.config b/TechTest/AnyCompany.Tests/packages.config new file mode 100644 index 0000000..7afc9a2 --- /dev/null +++ b/TechTest/AnyCompany.Tests/packages.config @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TechTest/AnyCompany/AnyCompany.csproj b/TechTest/AnyCompany/AnyCompany.csproj index 5b0498d..f835e03 100644 --- a/TechTest/AnyCompany/AnyCompany.csproj +++ b/TechTest/AnyCompany/AnyCompany.csproj @@ -1,18 +1,23 @@  + Debug AnyCPU - {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D} - Library - Properties + {E882A9A5-1265-4E61-9BBC-9A50989BA147} + Exe AnyCompany AnyCompany - v4.6.1 + v4.7.2 512 + true + true + + + AnyCPU true full false @@ -22,6 +27,7 @@ 4 + AnyCPU pdbonly true bin\Release\ @@ -30,8 +36,124 @@ 4 + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Bcl.HashCode.1.1.0\lib\net461\Microsoft.Bcl.HashCode.dll + + + ..\packages\Microsoft.Data.SqlClient.1.0.19269.1\lib\net46\Microsoft.Data.SqlClient.dll + + + ..\packages\Microsoft.Data.Sqlite.Core.3.1.6\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + + + ..\packages\Microsoft.DotNet.PlatformAbstractions.3.1.6\lib\net45\Microsoft.DotNet.PlatformAbstractions.dll + + + ..\packages\Microsoft.EntityFrameworkCore.3.1.6\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Memory.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll + + + ..\packages\Microsoft.Extensions.Configuration.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Configuration.Binder.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.3.1.6\lib\net461\Microsoft.Extensions.DependencyInjection.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.DependencyModel.3.1.6\lib\net451\Microsoft.Extensions.DependencyModel.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Options.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Primitives.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + + + ..\packages\Microsoft.Identity.Client.3.0.8\lib\net45\Microsoft.Identity.Client.dll + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Remotion.Linq.2.0.1\lib\net45\Remotion.Linq.dll + + + ..\packages\SQLitePCLRaw.core.2.0.2\lib\netstandard2.0\SQLitePCLRaw.core.dll + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll + + + ..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll + + + + + ..\packages\System.Data.Common.4.3.0\lib\net451\System.Data.Common.dll + True + True + + + ..\packages\System.Diagnostics.DiagnosticSource.4.7.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + + + ..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll + + + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + @@ -40,12 +162,47 @@ - - - - - + + + + + + + + + + + + + + + + 202008071042307_firstcommit.cs + + + + + + + + + 202008071042307_firstcommit.cs + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/TechTest/AnyCompany/App.config b/TechTest/AnyCompany/App.config new file mode 100644 index 0000000..95b941b --- /dev/null +++ b/TechTest/AnyCompany/App.config @@ -0,0 +1,82 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TechTest/AnyCompany/BUL/Helpers/BusinessRulesHelper.cs b/TechTest/AnyCompany/BUL/Helpers/BusinessRulesHelper.cs new file mode 100644 index 0000000..4eea22c --- /dev/null +++ b/TechTest/AnyCompany/BUL/Helpers/BusinessRulesHelper.cs @@ -0,0 +1,17 @@ +namespace AnyCompany.BUL.Helpers +{ + public static class BusinessRulesHelper + { + public static decimal DetermineVat(string Country) + { + //Country should be made into its on Model ideally as it could contain information about itself; Postal Code, City, Town etc + //"UK" should not be hardcoded or a string. There should be a dynamic but + //consistent source from which to pull these values from. Like a paid for "Countries" webservice or something. + return (decimal)(!string.IsNullOrEmpty(Country) && Country.ToUpper() == "UK" ? 0.2 : 0); + } + public static bool IsValidOrderAmount(decimal orderAmount) + { + return orderAmount > 0 ? true : false; + } + } +} diff --git a/TechTest/AnyCompany/BUL/Services/CustomerService.cs b/TechTest/AnyCompany/BUL/Services/CustomerService.cs new file mode 100644 index 0000000..6fa7a75 --- /dev/null +++ b/TechTest/AnyCompany/BUL/Services/CustomerService.cs @@ -0,0 +1,26 @@ +using AnyCompany.DAL; +using System.Collections.Generic; + +namespace AnyCompany.BUL.Services +{ + //Creating DataSource not responsibilty of Customer Service + public class CustomerService + { + private readonly ICustomerRepository _customerRepository; + public CustomerService(ICustomerRepository customerRepository) + { + _customerRepository = customerRepository; + } + + public Customer RetrieveACustomer(int CustomerId) + { + return _customerRepository.Get(CustomerId); + } + + //Return Customers with linked Orders by default + public IEnumerable RetrieveCustomers(bool includeOrders = true) + { + return _customerRepository.GetAll(includeOrders); + } + } +} diff --git a/TechTest/AnyCompany/BUL/Services/OrderService.cs b/TechTest/AnyCompany/BUL/Services/OrderService.cs new file mode 100644 index 0000000..4eb0f69 --- /dev/null +++ b/TechTest/AnyCompany/BUL/Services/OrderService.cs @@ -0,0 +1,43 @@ +using AnyCompany.BUL.Helpers; +using AnyCompany.DAL; +using System; + +namespace AnyCompany.BUL.Services +{ + //Creating DataSource not responsibilty of Order Service + public class OrderService + { + private readonly ICustomerRepository _customerRepository; + private readonly IOrderRepository _orderRepository; + public OrderService(IOrderRepository orderRepository, ICustomerRepository customerRepository) + { + _orderRepository = orderRepository; + _customerRepository = customerRepository; + } + + //Business Rules moved to central location + public bool PlaceOrder(Order order, int customerId) + { + if (!BusinessRulesHelper.IsValidOrderAmount(order.Amount)) + { + //Some DI logger here + Console.WriteLine("Order Amount should be greater than 0."); + return false; + } + + Customer customer = _customerRepository.Get(customerId); + if (_customerRepository.Get(customerId) == null) + { + //Some DI logger here + Console.WriteLine("No Customer found."); + return false; + } + else + { + order.VAT = BusinessRulesHelper.DetermineVat(customer.Country); + } + + return _orderRepository.Save(order); + } + } +} diff --git a/TechTest/AnyCompany/CustomerRepository.cs b/TechTest/AnyCompany/CustomerRepository.cs deleted file mode 100644 index e3de9b7..0000000 --- a/TechTest/AnyCompany/CustomerRepository.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Data.SqlClient; - -namespace AnyCompany -{ - public static class CustomerRepository - { - private static string ConnectionString = @"Data Source=(local);Database=Customers;User Id=admin;Password=password;"; - - public static Customer Load(int customerId) - { - Customer customer = new Customer(); - - SqlConnection connection = new SqlConnection(ConnectionString); - connection.Open(); - - SqlCommand command = new SqlCommand("SELECT * FROM Customer WHERE CustomerId = " + customerId, - connection); - var reader = command.ExecuteReader(); - - while (reader.Read()) - { - customer.Name = reader["Name"].ToString(); - customer.DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString()); - customer.Country = reader["Country"].ToString(); - } - - connection.Close(); - - return customer; - } - } -} diff --git a/TechTest/AnyCompany/DAL/Data/AnyCompanyContext.cs b/TechTest/AnyCompany/DAL/Data/AnyCompanyContext.cs new file mode 100644 index 0000000..ec53e85 --- /dev/null +++ b/TechTest/AnyCompany/DAL/Data/AnyCompanyContext.cs @@ -0,0 +1,14 @@ +using System; +using System.Configuration; +using System.Data.Entity; +namespace AnyCompany.DAL +{ + public class AnyCompanyContext : DbContext + { + public AnyCompanyContext() : base(@ConfigurationManager.ConnectionStrings["AnyCompanyConnection"]?.ConnectionString) + { + } + public DbSet Orders { get; set; } + public DbSet Customers { get; set; } + } +} \ No newline at end of file diff --git a/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.cs b/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.cs new file mode 100644 index 0000000..1d34be0 --- /dev/null +++ b/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.cs @@ -0,0 +1,44 @@ +namespace AnyCompany.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class firstcommit : DbMigration + { + public override void Up() + { + CreateTable( + "dbo.Customers", + c => new + { + CustomerId = c.Int(nullable: false, identity: true), + Country = c.String(), + DateOfBirth = c.DateTime(nullable: false), + Name = c.String(), + }) + .PrimaryKey(t => t.CustomerId); + + CreateTable( + "dbo.Orders", + c => new + { + OrderId = c.Int(nullable: false, identity: true), + CustomerId = c.Int(nullable: false), + Amount = c.Decimal(nullable: false, precision: 18, scale: 2), + VAT = c.Decimal(nullable: false, precision: 18, scale: 2), + }) + .PrimaryKey(t => t.OrderId) + .ForeignKey("dbo.Customers", t => t.CustomerId, cascadeDelete: true) + .Index(t => t.CustomerId); + + } + + public override void Down() + { + DropForeignKey("dbo.Orders", "CustomerId", "dbo.Customers"); + DropIndex("dbo.Orders", new[] { "CustomerId" }); + DropTable("dbo.Orders"); + DropTable("dbo.Customers"); + } + } +} diff --git a/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.designer.cs b/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.designer.cs new file mode 100644 index 0000000..251ef25 --- /dev/null +++ b/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.designer.cs @@ -0,0 +1,29 @@ +// +namespace AnyCompany.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.4.4")] + public sealed partial class firstcommit : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(firstcommit)); + + string IMigrationMetadata.Id + { + get { return "202008071042307_firstcommit"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.resx b/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.resx new file mode 100644 index 0000000..d0fe62e --- /dev/null +++ b/TechTest/AnyCompany/DAL/Data/Migrations/202008071042307_firstcommit.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAM1Z227jNhB9L9B/IPTUFtkoyb5sDXsXXicpjCZxECVB3wJGGjtEKVIlqcDGol/Wh35Sf6FD3SxRli+5LgIENjlzOByeGc7Q//3zb//LPObkEZRmUgy8w/0Dj4AIZcTEbOClZvrhk/fl848/9E+ieE5uS7mPVg41hR54D8YkPd/X4QPEVO/HLFRSy6nZD2Xs00j6RwcHv/qHhz4ghIdYhPSvUmFYDNkX/DqSIoTEpJSfywi4LsZxJshQyQWNQSc0hIE3FIuRjBMqFvvHwzOPDDmjaEUAfOoRKoQ01KCNvRsNgVFSzIIEByi/XiSAclPKNRS295bi227j4Mhuw18qllBhqo2MdwQ8/Fj4xXfVn+Rdr/Ibeu4EPWwWdteZ9wbeKFsClEfcxXojrqxgw7ml+B5ZDu5VDECi2L89Mkq5SRUMBKRGUb5HLtN7zsLfYXEt/wQxECnndbvQMpxrDODQpZIJKLO4gqlj7TjyiN/U912ASn2Fbr6vsTAfjzxygcbQew4VDWo+CIxU8BsIUNRAdEmNAYWnOI4gc2TLCndNiZRWi3JBpB5GkEfO6fwMxMw8DDz86JFTNoeoHCmMuBEMAw6VjEph0zrHaN1k+pUp81CuZYeuMZpW7G89lv3/8gZf0Ec2y3zqLDdREbLHI1fAs2n9wJI8cCuy3ZUyp0rGV5LXDrOYugtkqkJrtlw9f03VDEzTqr6/jIa1MZJhbBkgmew7RUe29lNCo1J8s7jYOhbX4wxjG2AV5SFkMeUeuVT4qbi7PnkkCKlF3B3+dnj9QthdXBtqLUOW+dRxTUn6poEnIiIbIiAP3Hr8YPwi41iCHEMT0G7P5dJEHAMHA2QY5tfUiOqQRm0H4TaibS0qY65mURFJTXN+aa2ClAZlmUQ5FgEag4QJ0+Y/EyFLKF/vEEdtx2vFbrlayJ05hgSEZfx6Bzzfgmoh5zA2+anv1/jVTnGoY1ADVBlNVdKyMzA3K3IeFlBF2tNFpnfpYJEDMM7GMHsvI6DFT389SJn/WwgFnxz12qbbhlSXSU2q475xz2Fz8FWGNzbeOtDNMVMDKu11I7G5yxW5pjreZeHs55VzWWH7HSV2/5wmCV78tZK7GCFBXm+PPgS7F6NxjuGHekVNWllbrYRXDJ2BM2trqghOmdIGKxx6T22mHUVxS6xN5g6Oleu5fG0fWkm+UsN+diPHth9LYrdDv9A9xa3FNnNkF+kK2rRVs76HcqrW3KUjydNYbE4pa9DKirUBVQ5uj9OoSOtYjYnt8fKqtA6Uj7QR+r7j41Y6bZ1k645rUmMr4nTmjK1Zkyez3SnTodflyarYqzuzo3Rcy5QX5V1ZydWRyrHtUbKCrQ6RDbwxR1r51xWpVq/ysJNv+0Xu2/zu0UqGuYgtU+Uji2wiDBbaQLxvBfaDv/iIM7BOLQXOqWBT0CZvPbyjg8Mj5/nk+3nK8LWO+JbvGe/+usCslzf2STt2JM6DgnikKnyg6qeYzn+ugz3x0SDCIfPcR4MdjNqxBX/Hnvh1TnM1aVpF9xiL//nA+5ap9cj4j7ul5h7JLO2RA/L3M/vn6BX752div17//J4dc9G+vHGD/JYtcVdN8512wO3eYrvudm1zm1/JGAL3Es86p3hnd7i69+1ufVeBd3SMb9cWr2yE1/bBjV3WqtpX6Xrb1RUSqfbbE7JYs9kSwv4SJSBsUKiSGYupLNnsWFSKOFnxHAzFi5YOlWFTGhqcDkHr7KH9lvIURU7ie4jGYpKaJDW4ZYjveaP9shGxbv2stW/a3J8k2fv6S2wBzWS2VpiIrynjUWX36YrM3QFhQ624Su1ZGnulzhYV0oUUWwIV7qsyxDXECUcwPREBfYSn2Haj4QxmNFyURXI3yOaDaLq9f8zoTNFYFxhLffyKHI7i+ef/AeNazcOCHQAA + + + dbo + + \ No newline at end of file diff --git a/TechTest/AnyCompany/DAL/Data/Migrations/Configuration.cs b/TechTest/AnyCompany/DAL/Data/Migrations/Configuration.cs new file mode 100644 index 0000000..2b746c2 --- /dev/null +++ b/TechTest/AnyCompany/DAL/Data/Migrations/Configuration.cs @@ -0,0 +1,70 @@ +namespace AnyCompany.Migrations +{ + using AnyCompany.DAL; + using System; + using System.Collections.Generic; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using System.Linq; + + internal sealed class Configuration : DbMigrationsConfiguration + { + public Configuration() + { + AutomaticMigrationsEnabled = false; + } + + protected override void Seed(AnyCompanyContext context) + { + List dummyCustomersWithOrders = new List + { + new Customer + { + Name = "I Have 1 Order", Country = "NM", DateOfBirth = DateTime.Parse("1987-06-01") + , Orders = new List() + { + new Order + { + Amount = 500, + VAT = 1 + } + } + }, + new Customer + { + Name = "I have zero Orders", Country = "ZA", DateOfBirth = DateTime.Parse("1985-09-11") + , Orders = new List() + { + new Order + { + Amount = 450, + VAT = 12 + } + } + }, + new Customer + { + Name = "I Have 2 Orders", Country = "ZW", DateOfBirth = DateTime.Parse("1925-06-01") + , Orders = new List() + { + new Order + { + Amount = 6799, + VAT = 4 + } + + , + new Order + { + Amount = 650, + VAT = 5 + } + } + } + }; + + context.Customers.AddRange(dummyCustomersWithOrders); + context.SaveChanges(); + } + } +} diff --git a/TechTest/AnyCompany/DAL/Interfaces/ICustomerRepository.cs b/TechTest/AnyCompany/DAL/Interfaces/ICustomerRepository.cs new file mode 100644 index 0000000..2e9e69b --- /dev/null +++ b/TechTest/AnyCompany/DAL/Interfaces/ICustomerRepository.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace AnyCompany.DAL +{ + public interface ICustomerRepository + { + Customer Get(int CustomerId); + IEnumerable GetAll(bool includeOrders = true); + } +} diff --git a/TechTest/AnyCompany/DAL/Interfaces/IOrderRepository.cs b/TechTest/AnyCompany/DAL/Interfaces/IOrderRepository.cs new file mode 100644 index 0000000..bec6f42 --- /dev/null +++ b/TechTest/AnyCompany/DAL/Interfaces/IOrderRepository.cs @@ -0,0 +1,8 @@ + +namespace AnyCompany.DAL +{ + public interface IOrderRepository + { + bool Save(Order order); + } +} diff --git a/TechTest/AnyCompany/Customer.cs b/TechTest/AnyCompany/DAL/Models/Customer.cs similarity index 51% rename from TechTest/AnyCompany/Customer.cs rename to TechTest/AnyCompany/DAL/Models/Customer.cs index aa994b6..c7bda3d 100644 --- a/TechTest/AnyCompany/Customer.cs +++ b/TechTest/AnyCompany/DAL/Models/Customer.cs @@ -1,13 +1,16 @@ using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; namespace AnyCompany { public class Customer { + [Key] + public int CustomerId { get; set; } public string Country { get; set; } - public DateTime DateOfBirth { get; set; } - public string Name { get; set; } + public List Orders { get; set; } = new List(); } } diff --git a/TechTest/AnyCompany/DAL/Models/Order.cs b/TechTest/AnyCompany/DAL/Models/Order.cs new file mode 100644 index 0000000..0af961d --- /dev/null +++ b/TechTest/AnyCompany/DAL/Models/Order.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace AnyCompany +{ + public class Order + { + [Key] + public int OrderId { get; set; } + + //[ForeignKey("Order")] + public int CustomerId { get; set; } + public decimal Amount { get; set; } + public decimal VAT { get; set; } + } +} diff --git a/TechTest/AnyCompany/DAL/Repositories/CustomerRepository.cs b/TechTest/AnyCompany/DAL/Repositories/CustomerRepository.cs new file mode 100644 index 0000000..d57871d --- /dev/null +++ b/TechTest/AnyCompany/DAL/Repositories/CustomerRepository.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Data.Entity; +using System.Data.SqlClient; +using System.Linq; + +namespace AnyCompany.DAL.Repositories +{ + internal static class CustomerRepository + { + public static Customer Get(int CustomerId) + { + try + { + using (AnyCompanyContext anyCompanyContext = new AnyCompanyContext()) + { + return anyCompanyContext.Customers.SingleOrDefault(c => c.CustomerId == CustomerId); + } + } + catch (SqlException ex) + { + //Logger here + Console.WriteLine(ex.Message); + } + catch (Exception ex) + { + //Logger here + Console.WriteLine(ex.Message); + } + return null; + } + public static IEnumerable GetAll(bool includeOrders = true) + { + try + { + using (AnyCompanyContext anyCompanyContext = new AnyCompanyContext()) + { + return includeOrders ? anyCompanyContext.Customers.Include(c => c.Orders).ToList() : anyCompanyContext.Customers.ToList(); + } + } + catch (SqlException ex) + { + //Injected Logger + Console.WriteLine(ex.Message); + } + catch (Exception ex) + { + //Injected Logger + Console.WriteLine(ex.Message); + } + return null; + } + } +} diff --git a/TechTest/AnyCompany/DAL/Repositories/CustomerRepositoryWrapper.cs b/TechTest/AnyCompany/DAL/Repositories/CustomerRepositoryWrapper.cs new file mode 100644 index 0000000..d3e2fee --- /dev/null +++ b/TechTest/AnyCompany/DAL/Repositories/CustomerRepositoryWrapper.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace AnyCompany.DAL.Repositories +{ + public class CustomerRepositoryWrapper : ICustomerRepository + { + public Customer Get(int CustomerId) + { + //Use a mapper like AutoMapper here to change Model to user friendly DTO if necessary + return CustomerRepository.Get(CustomerId); + } + + public IEnumerable GetAll(bool includeOrders = true) + { + //Use a mapper like AutoMapper here to change Model to user friendly DTO if necessary + return CustomerRepository.GetAll(includeOrders); + } + } +} diff --git a/TechTest/AnyCompany/DAL/Repositories/OrderRepository.cs b/TechTest/AnyCompany/DAL/Repositories/OrderRepository.cs new file mode 100644 index 0000000..2f66f8f --- /dev/null +++ b/TechTest/AnyCompany/DAL/Repositories/OrderRepository.cs @@ -0,0 +1,29 @@ +using System; +using System.Data.SqlClient; + +namespace AnyCompany.DAL.Repositories +{ + internal class OrderRepository + { + internal bool Save(Order order) + { + try + { + using (AnyCompanyContext context = new AnyCompanyContext()) + { + context.Orders.Add(order); + return context.SaveChanges() > 0; + } + } + catch (SqlException ex) + { + Console.WriteLine(ex.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return false; + } + } +} diff --git a/TechTest/AnyCompany/DAL/Repositories/OrderRepositoryWrapper.cs b/TechTest/AnyCompany/DAL/Repositories/OrderRepositoryWrapper.cs new file mode 100644 index 0000000..7e38182 --- /dev/null +++ b/TechTest/AnyCompany/DAL/Repositories/OrderRepositoryWrapper.cs @@ -0,0 +1,11 @@ +namespace AnyCompany.DAL.Repositories +{ + public class OrderRepositoryWrapper : IOrderRepository + { + public bool Save(Order order) + { + //Use a mapper like AutoMapper here to change Model to user friendly DTO if necessary + return new OrderRepository().Save(order); + } + } +} diff --git a/TechTest/AnyCompany/Order.cs b/TechTest/AnyCompany/Order.cs deleted file mode 100644 index fec8e7b..0000000 --- a/TechTest/AnyCompany/Order.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace AnyCompany -{ - public class Order - { - public int OrderId { get; set; } - public double Amount { get; set; } - public double VAT { get; set; } - } -} diff --git a/TechTest/AnyCompany/OrderRepository.cs b/TechTest/AnyCompany/OrderRepository.cs deleted file mode 100644 index 3229885..0000000 --- a/TechTest/AnyCompany/OrderRepository.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Data.SqlClient; - -namespace AnyCompany -{ - internal class OrderRepository - { - private static string ConnectionString = @"Data Source=(local);Database=Orders;User Id=admin;Password=password;"; - - public void Save(Order order) - { - SqlConnection connection = new SqlConnection(ConnectionString); - connection.Open(); - - SqlCommand command = new SqlCommand("INSERT INTO Orders VALUES (@OrderId, @Amount, @VAT)", connection); - - command.Parameters.AddWithValue("@OrderId", order.OrderId); - command.Parameters.AddWithValue("@Amount", order.Amount); - command.Parameters.AddWithValue("@VAT", order.VAT); - - command.ExecuteNonQuery(); - - connection.Close(); - } - } -} diff --git a/TechTest/AnyCompany/OrderService.cs b/TechTest/AnyCompany/OrderService.cs deleted file mode 100644 index ebfb103..0000000 --- a/TechTest/AnyCompany/OrderService.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace AnyCompany -{ - public class OrderService - { - private readonly OrderRepository orderRepository = new OrderRepository(); - - public bool PlaceOrder(Order order, int customerId) - { - Customer customer = CustomerRepository.Load(customerId); - - if (order.Amount == 0) - return false; - - if (customer.Country == "UK") - order.VAT = 0.2d; - else - order.VAT = 0; - - orderRepository.Save(order); - - return true; - } - } -} diff --git a/TechTest/AnyCompany/Program.cs b/TechTest/AnyCompany/Program.cs new file mode 100644 index 0000000..90389b2 --- /dev/null +++ b/TechTest/AnyCompany/Program.cs @@ -0,0 +1,38 @@ +using AnyCompany.BUL.Helpers; +using AnyCompany.BUL.Services; +using AnyCompany.DAL; +using AnyCompany.DAL.Repositories; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace AnyCompany +{ + class Program + { static void Main(string[] args) + { + CustomerService c = new CustomerService(new CustomerRepositoryWrapper()); + Customer customer = c.RetrieveACustomer(1); + if (customer != null) + { + Console.WriteLine("Customer is " + customer.Name); + Console.WriteLine(); + + IEnumerable customers = c.RetrieveCustomers(true); + Console.WriteLine("Customers are:"); + customers.ToList().ForEach(i => Console.Write("Name: {0}\t Order counts: {1}\n", i.Name, i.Orders.Count)); + + Console.WriteLine("\n\n============================="); + OrderService s = new OrderService(new OrderRepositoryWrapper(), new CustomerRepositoryWrapper()); + Order order = new Order { Amount = 2456, CustomerId = customer.CustomerId, VAT = BusinessRulesHelper.DetermineVat(customer.Country) }; + bool result = s.PlaceOrder(order, customer.CustomerId); + Console.WriteLine("Added Order succesfully = " + result); + } + else + { + Console.WriteLine("Could be no data in the DB... Mmm.."); + } + Console.ReadKey(); + } + } +} diff --git a/TechTest/AnyCompany/Properties/AssemblyInfo.cs b/TechTest/AnyCompany/Properties/AssemblyInfo.cs index bcdfb17..794f339 100644 --- a/TechTest/AnyCompany/Properties/AssemblyInfo.cs +++ b/TechTest/AnyCompany/Properties/AssemblyInfo.cs @@ -8,9 +8,9 @@ [assembly: AssemblyTitle("AnyCompany")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Investec Bank")] +[assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AnyCompany")] -[assembly: AssemblyCopyright("Copyright © Investec Bank 2018")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,7 +20,7 @@ [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c7e15594-7d8f-4c18-9dd7-14f3fbb1572d")] +[assembly: Guid("e882a9a5-1265-4e61-9bbc-9a50989ba147")] // Version information for an assembly consists of the following four values: // diff --git a/TechTest/AnyCompany/Properties/Settings.Designer.cs b/TechTest/AnyCompany/Properties/Settings.Designer.cs new file mode 100644 index 0000000..65b88b7 --- /dev/null +++ b/TechTest/AnyCompany/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace AnyCompany.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/TechTest/AnyCompany/Properties/Settings.settings b/TechTest/AnyCompany/Properties/Settings.settings new file mode 100644 index 0000000..049245f --- /dev/null +++ b/TechTest/AnyCompany/Properties/Settings.settings @@ -0,0 +1,6 @@ + + + + + + diff --git a/TechTest/AnyCompany/packages.config b/TechTest/AnyCompany/packages.config new file mode 100644 index 0000000..b3b266b --- /dev/null +++ b/TechTest/AnyCompany/packages.config @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TechTest/TechTest.sln b/TechTest/TechTest.sln index 1c1c57a..7058c9a 100644 --- a/TechTest/TechTest.sln +++ b/TechTest/TechTest.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27004.2005 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30330.147 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany", "AnyCompany\AnyCompany.csproj", "{C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany", "AnyCompany\AnyCompany.csproj", "{E882A9A5-1265-4E61-9BBC-9A50989BA147}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Tests", "AnyCompany.Tests\AnyCompany.Tests.csproj", "{CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Tests", "AnyCompany.Tests\AnyCompany.Tests.csproj", "{60CFE149-CB3F-4227-8EAD-4E16C0796535}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B6D3C1BB-2A37-4E17-9EE3-DEF28286E782}" ProjectSection(SolutionItems) = preProject @@ -18,14 +18,14 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Release|Any CPU.Build.0 = Release|Any CPU - {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Release|Any CPU.Build.0 = Release|Any CPU + {E882A9A5-1265-4E61-9BBC-9A50989BA147}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E882A9A5-1265-4E61-9BBC-9A50989BA147}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E882A9A5-1265-4E61-9BBC-9A50989BA147}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E882A9A5-1265-4E61-9BBC-9A50989BA147}.Release|Any CPU.Build.0 = Release|Any CPU + {60CFE149-CB3F-4227-8EAD-4E16C0796535}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60CFE149-CB3F-4227-8EAD-4E16C0796535}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60CFE149-CB3F-4227-8EAD-4E16C0796535}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60CFE149-CB3F-4227-8EAD-4E16C0796535}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TechTest/package-lock.json b/TechTest/package-lock.json new file mode 100644 index 0000000..48e341a --- /dev/null +++ b/TechTest/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +}