diff --git a/BasicApp.App/BasicApp.App.csproj b/BasicApp.App/BasicApp.App.csproj
new file mode 100644
index 0000000..f8fbd44
--- /dev/null
+++ b/BasicApp.App/BasicApp.App.csproj
@@ -0,0 +1,225 @@
+
+
+
+ Debug
+ x86
+ 8.0.30703
+ 2.0
+ {F7EBFB21-F051-4053-B3F9-D5545CC506D3}
+ Exe
+ Properties
+ BasicApp.App
+ BasicApp.App
+ v4.0
+ Client
+ 512
+ ..\..\
+ true
+
+
+ x86
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ x86
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\CollectionGen.dll
+ True
+
+
+ ..\..\packages\dotless.1.2.2.0\lib\dotless.Core.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\ICSharpCode.SharpZipLib.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\Interop.MsmMergeTypeLib.dll
+ True
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\Interop.StarTeam.dll
+ True
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\Interop.WindowsInstaller.dll
+ True
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\log4net.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.exe
+ .exe
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.CompressionTasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.Contrib.Tasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.Core.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.DotNetTasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.Extensions.Tasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.MSNetTasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.SourceControlTasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.VisualCppTasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.VSNetTasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAnt.Win32Tasks.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NAntContrib.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\NDoc.Documenter.NAnt.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\scvs.exe
+ .exe
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\SLiNgshoT.exe
+ .exe
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\SLiNgshoT.Core.dll
+ True
+
+
+ ..\packages\NAnt.Extensions.0.1.2.4\lib\SourceSafe.Interop.dll
+ True
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable 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/BasicApp.App/Program.cs b/BasicApp.App/Program.cs
new file mode 100644
index 0000000..f25100c
--- /dev/null
+++ b/BasicApp.App/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using BasicApp.App.Utilities;
+
+namespace BasicApp.Main
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ UtilitiesDate utility = new UtilitiesDate();
+ utility.SetMonthsUsingWriterInput("emptyFile.txt");
+ Console.WriteLine(utility.GetMonths());
+ Console.WriteLine(utility.GetWeeks(DateTime.Now.AddDays(-42), DateTime.Now));
+ Console.WriteLine(utility.GetDays(DateTime.Now.AddDays(-42), DateTime.Now));
+ Console.WriteLine("Press enter to close...");
+ Console.ReadLine();
+ }
+ }
+}
diff --git a/BasicApp.App/Properties/AssemblyInfo.cs b/BasicApp.App/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8708bff
--- /dev/null
+++ b/BasicApp.App/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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("BasicApp.App")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("BasicApp.App")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
+[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("fa8a923b-9fb8-4092-a783-ed0220a848eb")]
+
+// 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/BasicApp.App/Utilities.cs b/BasicApp.App/Utilities.cs
new file mode 100644
index 0000000..dda7c4f
--- /dev/null
+++ b/BasicApp.App/Utilities.cs
@@ -0,0 +1,386 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace BasicApp.App.Utilities
+{
+ public class UtilitiesProfession
+ {
+ public enum Gender
+ {
+ Male = 1,
+ Female = 2
+ }
+
+ public string GetCompleteProfession(string professionName, Gender g)
+ {
+ string StrPronoun = string.Empty;
+
+ if (g == Gender.Male)
+ StrPronoun = "he";
+ else
+ StrPronoun = "she";
+
+ if (Regex.IsMatch(professionName, "^[aeiou]"))
+ return StrPronoun + " is an " + professionName;
+ else
+ return StrPronoun + " is a " + professionName;
+ }
+ }
+
+ public class UtilitiesDate
+ {
+ private IReader _Reader;
+ private IWriter _Writer;
+ private string _MonthsAsString;
+
+ private void SetMonthsAsString()
+ {
+ _MonthsAsString = "";
+ _MonthsAsString += "January\r\nFebruary\r\nMarch\r\n";
+ _MonthsAsString += "April\r\nMay\r\nJune\r\n";
+ _MonthsAsString += "July\r\nAugust\r\nSeptember\r\n";
+ _MonthsAsString += "October\r\nNovember\r\nDecember";
+ }
+
+ // Default Constructor
+
+ public UtilitiesDate(){
+ SetMonthsAsString();
+ }
+
+ // Get time difference in weeks or days from DateTime t1 to DateTime t2.
+
+ public decimal GetWeeks(DateTime dtFrom, DateTime dtTo)
+ {
+ int Days = ((TimeSpan)(dtTo - dtFrom)).Days;
+ decimal Weeks = Math.Ceiling((decimal)Days / 7);
+ return Weeks;
+ }
+ public decimal GetDays(DateTime dtFrom, DateTime dtTo)
+ {
+ int Days = ((TimeSpan)(dtTo - dtFrom)).Days;
+ return Days;
+ }
+
+ /*********************/
+ /* STUBS: CASE STUDY */
+ /*********************/
+
+ /* There are multiple ways by which we can inject stubs into our code, the challenge is choosing
+ * the correct location for the "seam", which is defined as a place where we can choose either
+ * a fake or the real to use in execution.
+ *
+ * The following stub injection tricks, explored in The Art of Unit Testing, are shown here and will
+ * be the center of this study.
+ *
+ * Injection by Parameter
+ * Injection by Constructor
+ * Injection by Property Setters
+ * Injection using Factory
+ * Injection using Local Factory (Extract & Override)
+ */
+
+ /* The following method reads a simple project text file that contains all the months listed in order.
+ * It will return an array of strings where each element is the name of a month. We will use it as a test
+ * case.
+ */
+ public string[] GetMonths()
+ {
+ IReader Reader = new FileReader();
+ string Months = Reader.ValidateAndRead("file.txt");
+ return Regex.Split(Months, "\r\n");
+ }
+
+ /* INJECTION BY PARAMETER
+ *
+ * Simple & trival way to inject stub, but you might not want to expose dependency on
+ * reader in public method. Not much else to say.
+ */
+ public string[] GetMonthsStubByParamInject(IReader reader)
+ {
+ string Months = reader.ValidateAndRead("file.txt");
+ return Regex.Split(Months, "\r\n");
+ }
+
+ /* INJECTION BY CONSTRUCTOR
+ *
+ * Simple but won't scale well as more stubs will require more properties which means more constructors
+ * and method arguements in constructors. Besides being messy it also leads to potential
+ * time wasting. Imagine that you have 50 tests against the constructor and you find a new dependency
+ * that requires a stub. You'll need to add a parameter to the constructor in all those tests.
+ *
+ * A few potential solutions to constructor injection may include ...
+ *
+ * To handle neatness: a special wrapper function that locally defines values needed to initialize a class.
+ * And only one paramter is needed to define the class type.
+ *
+ * To handle dependancy issues: Inversion of Control (IoC). A construct where you "say" what you want and it goes "back"
+ * to initialize the needed dependencies to then give you what you want. More details can be found here.
+ * http://www.hanselman.com/blog/ListOf-NETDependencyInjectionContainersIOC.aspx.
+ */
+
+ public UtilitiesDate(IReader reader)
+ {
+ _Reader = reader;
+ SetMonthsAsString();
+ }
+
+ public string[] GetMonthsStubByConstructorInject() {
+ string Months = _Reader.ValidateAndRead("file.txt");
+ return Regex.Split(Months, "\r\n");
+ }
+
+ /* INJECTION BY PROPERTY SETTERS
+ *
+ * Our method is no different than before but now we can set our reader outside of the constructor.
+ * We make it explicity clear that the reader is optional and keep our constructors clean and simple.
+ */
+
+ public IReader Reader
+ {
+ get { return _Reader; }
+ set { _Reader = value; }
+ }
+
+ public string[] GetMonthsStubByPropertyInject() {
+ string Months = _Reader.ValidateAndRead("file.txt");
+ return Regex.Split(Months, "\r\n");
+ }
+
+ /* INJECTION USING FACTORY
+ *
+ * It be cool if we could get our stub locally, right before the actual function call we are testing, instead of
+ * relying on global fields. To do this we need a factory. The factory class will now be responsible for generating
+ * our object. It will contain the seam in our code (the point at which we can generate a fake or a real). Since it's
+ * static we can define what ReaderFactory will output on Create.
+ */
+
+ public string[] GetMonthsStubUsingFactory() {
+ _Reader = ReaderFactory.Create();
+ string Months = _Reader.ValidateAndRead("file.txt");
+ return Regex.Split(Months, "\r\n");
+ }
+
+ /* One of the important concepts to understand within unit tests are the layers of indirection. Whenever you test you are always
+ * testing a certain layer of your program. Whether it be the main function or a subroutine on the extremity of the application you
+ * are always somewhere within the call stack. Typically the deeper you go the more control you have over what you are testing but on
+ * the other hand these low level tests are obscure and difficult to understand.
+ *
+ * Choosing where you want to place the seams is one of the major challenges of developing good unit tests.
+ *
+ * Thus far we have looked at two important locations where seams (specifically fakes) can be introduced.
+ *
+ * Firstly we looked at choosing to fake the members in the tested class. One of the key issues here is that we are
+ * changing the semantics of the code within the class we are testing, more importantly how it must be used.
+ *
+ * Secondly we looked at choosing to fake the members inside of the factory class and with that we managed to avoided changing the
+ * code inside the class which we are testing.
+ */
+
+
+ /* INJECTION USING LOCAL FACTORY (EXTRACT AND OVERRIDE)
+ *
+ * Is an easy way to avoid depedancy issues when creating stubs by using a derivation of the class that is under test. We can
+ * call the derived version the "testable" class. It's incredible clean and simple, it should be your default technique for stub
+ * creation. The only time when you might want to use the other techniques is if the code base is already supportive of the other
+ * techniques. For example there's an interface available for faking (you don't need to make one) or a location in the code where a
+ * seam can be injected.
+ */
+
+ protected virtual IReader GetReader()
+ {
+ return new FileReader();
+ }
+
+ public string[] GetMonthsStubUsingLocalFactory()
+ {
+ _Reader = GetReader();
+ string Months = _Reader.ValidateAndRead("file.txt");
+ return Regex.Split(Months, "\r\n");
+ }
+
+ /* One problem with Testable Object Oriented Design (TOOD) is that it requires a lot of exposure of a class's internals. Arguably this counters
+ * the encapsalation principle. If you feel making extra public getters, setters and constructors for testing isn't the way you want to go
+ * you can always make these methods internal (over public) and use conditional attributes to make sure they are only used during
+ * debug builds. Having these in your code will make it less readable, primary reason I didn't include them here, but it's an option
+ * if security and testing are both essential.
+ */
+
+ /*********************/
+ /* MOCKS: CASE STUDY */
+ /*********************/
+
+ /* The difference between mocks and stubs can seem subtle at times. A mock is an object
+ * that we can use for assertion. When object A interacts with object B that should lead to a
+ * certain state change in B, if it doesn't the interaction failed. In this scenario we can make a
+ * mock of B. A more technical difference between mocks and stubs is that a correctly written stub can never
+ * make a test fail, but a mock can.
+ *
+ * The following Mocking techniques are explored.
+ *
+ * Use of Manually Written Mocks (Reference test code for documentation)
+ * Use of Strict Mocks (Reference test code for documentation)
+ * Use of Non-Strict Mocks (Reference test code for documentation)
+ * Use of Stubs (Reference test code for documentation)
+ * Constraints (Reference test code for documentation)
+ * Delegates (Reference test code for documentation)
+ * AAA (Arrange, Assert, Act) (Reference test code for documentation)
+ *
+ */
+
+ /* The following method will be used as a test case, like the previously defined getMonths, except this time we
+ * will be using it to test mocks. The method will simply write all the months in year to a file in the designated
+ * path. Each month will be written on a new line. If we successfully manage to write we return true else we return false.
+ * An important note here is that we aren't mocking the file system but rather the object that makes the low level
+ * call to write to the file system.
+ */
+
+ protected virtual IWriter GetWriter()
+ {
+ return new FileWriter();
+ }
+
+ public bool SetMonths(string path)
+ {
+ _Writer = GetWriter();
+ if (_Writer.ValidateAndWrite(path, _MonthsAsString))
+ return true;
+ else
+ return false;
+ }
+
+ public bool SetMonthsUsingWriterInput(string path)
+ {
+ _Writer = GetWriter();
+ if (_Writer.ValidateAndWrite(new WriterInput(path, _MonthsAsString)))
+ return true;
+ else
+ return false;
+ }
+ }
+
+ /*MANUALLY WRITTEN STUB*/
+
+ public interface IReader
+ {
+ string ValidateAndRead(string path);
+ }
+
+ public class FileReader : IReader
+ {
+ public string ValidateAndRead(string path)
+ {
+ return System.IO.File.ReadAllText(path);
+ }
+ }
+
+ public class StubReader : IReader
+ {
+ public string ValidateAndRead(string path)
+ {
+ string S = "";
+ S += "January\r\nFebruary\r\nMarch\r\n";
+ S += "April\r\nMay\r\nJune\r\n";
+ S += "July\r\nAugust\r\nSeptember\r\n";
+ S += "October\r\nNovember\r\nDecember";
+ return S;
+ }
+ }
+
+ /*MANUALLY WRITTEN MOCK*/
+ public interface IWriter
+ {
+ bool ValidateAndWrite(string path, string content);
+ bool ValidateAndWrite(WriterInput input);
+ }
+
+ public class FileWriter : IWriter
+ {
+ public bool ValidateAndWrite(string path, string content)
+ {
+ try {
+ System.IO.File.WriteAllText(path, content);
+ return true;
+ } catch {
+ return false;
+ }
+ }
+
+ public bool ValidateAndWrite(WriterInput input) {
+ // parse the WriterInput object and do the same as before
+ return true;
+ }
+ }
+
+ public class MockWriter : IWriter
+ {
+ public string _Path;
+ public string _Content;
+ public bool ValidateAndWrite(string path, string content)
+ {
+ _Path = path;
+ _Content = content;
+ return true;
+ }
+
+ public bool ValidateAndWrite(WriterInput input){
+ // parse the WriterInput object and do the same as before
+ return true;
+ }
+ }
+
+ /*HELPERS*/
+
+ public class WriterInput
+ {
+ private string _Path;
+ private string _Content;
+
+ public string Path
+ {
+ get {return _Path; }
+ set {_Path = value;}
+ }
+
+ public string Content
+ {
+ get { return _Content; }
+ set { _Content = value; }
+ }
+
+ public WriterInput(string path, string content) {
+ _Path = path;
+ _Content = content;
+ }
+ }
+
+ public class ReaderFactory
+ {
+ private static IReader _Reader = null;
+
+ public static IReader Create() {
+ if (_Reader != null)
+ return _Reader;
+ else
+ return new FileReader();
+ }
+
+ public static void SetReader(IReader reader){
+ _Reader = reader;
+ }
+ }
+
+ public class TestableUtilitiesDate : UtilitiesDate {
+ public IReader _Reader;
+ public IWriter _Writer;
+
+ protected override IReader GetReader() {
+ return _Reader;
+ }
+
+ protected override IWriter GetWriter()
+ {
+ return _Writer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BasicApp.App/packages.config b/BasicApp.App/packages.config
new file mode 100644
index 0000000..22730fb
--- /dev/null
+++ b/BasicApp.App/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BasicApp.Test/BasicApp.Test.csproj b/BasicApp.Test/BasicApp.Test.csproj
new file mode 100644
index 0000000..f4b7b3d
--- /dev/null
+++ b/BasicApp.Test/BasicApp.Test.csproj
@@ -0,0 +1,76 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {26911987-92C3-4F66-8E05-C82689C0B181}
+ Library
+ Properties
+ BasicApp.Test
+ BasicApp.Test
+ v4.0
+ 512
+ ..\..\
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ .exe
+ ..\..\..\..\builds\BasicApp\src\BasicApp.App\bin\Release\BasicApp.App.exe
+
+
+
+ ..\..\packages\RhinoMocks.3.6.1\lib\net\Rhino.Mocks.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable 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/BasicApp.Test/Properties/AssemblyInfo.cs b/BasicApp.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3c8d28c
--- /dev/null
+++ b/BasicApp.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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("BasicApp.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("BasicApp.Test")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
+[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("eaaee4a9-7516-4ab1-8a10-956c562c2cc6")]
+
+// 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/BasicApp.Test/UtilitiesUnderTest.cs b/BasicApp.Test/UtilitiesUnderTest.cs
new file mode 100644
index 0000000..8d211bd
--- /dev/null
+++ b/BasicApp.Test/UtilitiesUnderTest.cs
@@ -0,0 +1,341 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Rhino.Mocks;
+using Rhino.Mocks.Constraints;
+using BasicApp.App.Utilities;
+
+namespace BasicApp.Test.UtilitiesUnderTest
+{
+ [TestFixture]
+ class ProfessionUtilitiesUnderTest
+ {
+ private UtilitiesProfession _ObjUtil = null;
+
+ [SetUp]
+ public void Setup()
+ {
+ _ObjUtil = new UtilitiesProfession();
+ }
+
+ [Test]
+ public void GetCompleteProfession_Return_SheIsASoftwareEngineer()
+ {
+ string StrResult = _ObjUtil.GetCompleteProfession("software engineer", UtilitiesProfession.Gender.Female);
+ StringAssert.AreEqualIgnoringCase("She is a software engineer", StrResult);
+ }
+
+ [Test]
+ public void GetCompleteProfession_Return_HeIsAProjectManager()
+ {
+ string StrResult = _ObjUtil.GetCompleteProfession("software engineer", UtilitiesProfession.Gender.Male);
+ StringAssert.AreEqualIgnoringCase("He is a software engineer", StrResult);
+ }
+
+ [Test]
+ public void GetCompleteProfession_Return_HeIsAnEngineer()
+ {
+ string StrResult = _ObjUtil.GetCompleteProfession("engineer", UtilitiesProfession.Gender.Male);
+ StringAssert.AreEqualIgnoringCase("He is an engineer", StrResult);
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ _ObjUtil = null;
+ }
+ }
+
+ [TestFixture]
+ class DateUtilitiesUnderTest
+ {
+ private MockRepository _Mocks = null;
+ private UtilitiesDate _ObjUtil = null;
+ private TestableUtilitiesDate _ObjUtilTestable = null;
+ private StubReader _Reader = null;
+
+ private string[] _ExpectedMonths = null;
+ private string _ExpectedMonthsAsString = null;
+
+ [SetUp]
+ public void Setup()
+ {
+ _Mocks = new MockRepository();
+ _ObjUtil = new UtilitiesDate();
+ _ObjUtilTestable = new TestableUtilitiesDate();
+ _Reader = new StubReader();
+
+ _ExpectedMonths =
+ new string[12]
+ {"January", "February", "March",
+ "April", "May", "June",
+ "July", "August", "September",
+ "October", "November", "December"
+ };
+
+ _ExpectedMonthsAsString
+ = string.Join("\r\n", _ExpectedMonths);
+ }
+
+ [Test]
+ public void GetWeeks_Return_6()
+ {
+ decimal Weeks = _ObjUtil.GetWeeks(DateTime.Now.AddDays(-42), DateTime.Now);
+ Assert.AreEqual(6, Weeks);
+ }
+
+ [Test]
+ public void GetDays_Return_25()
+ {
+ decimal Days = _ObjUtil.GetDays(DateTime.Now.AddDays(-25), DateTime.Now);
+ Assert.AreEqual(25, Days);
+ }
+
+ [Test]
+ public void GetMonths_Returns_All_Months_InjectStub_ByParamPass()
+ {
+ string [] Months = _ObjUtil.GetMonthsStubByParamInject(_Reader);
+ Assert.AreEqual(_ExpectedMonths, Months);
+ }
+
+ [Test]
+ public void GetMonths_Returns_All_Months_InjectStub_ByConstuctor()
+ {
+ _ObjUtil = new UtilitiesDate(_Reader);
+ string[] Months = _ObjUtil.GetMonthsStubByConstructorInject();
+ Assert.AreEqual(_ExpectedMonths, Months);
+ }
+
+ [Test]
+ public void GetMonths_Returns_All_Months_InjectStub_ByPropertyInject()
+ {
+ _ObjUtil.Reader = _Reader;
+ string[] Months = _ObjUtil.GetMonthsStubByPropertyInject();
+ Assert.AreEqual(_ExpectedMonths, Months);
+ }
+
+ [Test]
+ public void GetMonths_Returns_All_Months_InjectStub_UsingFactory()
+ {
+ ReaderFactory.SetReader(_Reader);
+ string[] Months = _ObjUtil.GetMonthsStubUsingFactory();
+ Assert.AreEqual(_ExpectedMonths, Months);
+ }
+
+ [Test]
+ public void GetMonths_Returns_All_Months_InjectStub_UsingLocalFactory()
+ {
+ TestableUtilitiesDate ObjUtil = new TestableUtilitiesDate();
+ _ObjUtilTestable._Reader = _Reader;
+ string[] Months = _ObjUtilTestable.GetMonthsStubUsingFactory();
+ Assert.AreEqual(_ExpectedMonths, Months);
+ }
+
+ /* MANUALLY WRITTEN MOCKS
+ *
+ * Mocks, like stubs, need to be injected into the code. The very same strategies that were used for stubs
+ * can be used with mocks. Parameter, Constructor, Property, Factory, and Local Factory are all valid. Here
+ * is a test using manually written mocks. Here I use the local factory method.
+ */
+
+ [Test]
+ public void SetMonths_Proper_Content_Sent()
+ {
+ MockWriter Writer = new MockWriter();
+
+ _ObjUtilTestable._Writer = Writer;
+
+ _ObjUtilTestable.SetMonths("emptyFile.txt");
+
+ Assert.AreEqual(_ExpectedMonthsAsString,Writer._Content);
+ }
+
+ /* Isolation Frameworks are a great tool for saving time on having to manually create stubs and mocks.
+ * While they are rich in functionality it's still up to the programmer where mocks and stubs need to placed
+ * in the code. Poor placement of seams can lead to messy code and tests that are hard to understand.
+ */
+
+
+ /* STRICT MOCKS
+ *
+ * Strict mock objects require that the set expectations be met completely for
+ * the test to pass. This means that if any recorded call differs in either parameters
+ * or name the test will fail immediately. It won't wait till verify is called. One
+ * thing to note here is that because ValidateAndWrite is expected to return something
+ * we need to specify in our test code what will be returned after that line. Remember that
+ * writer is an empty shell!
+ *
+ * Means of Failure:
+ * -an unexpected method is called
+ * -an expected method is never called
+ */
+
+ [Test]
+ public void RhinoMock_SetMonths_Proper_Content_Sent_Strict()
+ {
+ // initialization
+ IWriter Writer = _Mocks.StrictMock();
+ _ObjUtilTestable._Writer = Writer;
+
+ // expecatation
+ using (_Mocks.Record())
+ {
+ Writer.ValidateAndWrite("emptyFile.txt", _ExpectedMonthsAsString);
+ LastCall.Return(true);
+ }
+
+ // invokation
+ _ObjUtilTestable.SetMonths("emptyFile.txt");
+
+ // verification
+ _Mocks.Verify(Writer);
+ }
+
+ /* NON-STRICT MOCKS
+ *
+ * Non-Strict mock objects require that the methods set in the expectation be called
+ * but it also allows other methods to be called. This makes the test less prone to
+ * failure.
+ *
+ * Means of Failure:
+ * -an expected method is never called
+ */
+
+ [Test]
+ public void RhinoMock_SetMonths_Proper_Content_Sent_NonStrict()
+ {
+ IWriter Writer = _Mocks.DynamicMock();
+ _ObjUtilTestable._Writer = Writer;
+
+ using (_Mocks.Record())
+ {
+ Writer.ValidateAndWrite("emptyFile.txt",_ExpectedMonthsAsString);
+ LastCall.Return(true);
+ }
+
+ _ObjUtilTestable.SetMonths("emptyFile.txt");
+
+ _Mocks.Verify(Writer);
+ }
+
+ /* USE OF STUBS
+ *
+ * Don't the let the name Rhino Mock fool you! this framework is capable of creating
+ * stubs as well as mocks!
+ */
+
+ [Test]
+ public void RhinoMock_GetMonths_Returns_All_Months()
+ {
+ IReader Reader = _Mocks.Stub();
+ _ObjUtilTestable._Reader = Reader;
+
+ // We set expectations purely to tell the stub what to return.
+ using (_Mocks.Record())
+ {
+ Reader.ValidateAndRead("file.txt");
+ LastCall.Return(_ExpectedMonthsAsString);
+ }
+
+ string[] Result = _ObjUtilTestable.GetMonthsStubUsingLocalFactory();
+
+ // If you verify the test will always pass, by definition stubs
+ // can't cause a test to fail, so we assert on something!
+ Assert.AreEqual(_ExpectedMonths, Result);
+ }
+
+ /* CONSTRAINTS
+ *
+ * We can also test the object properties of our parameters! Check more docs on constraints as
+ * they offer very rich functionality to the test code by allowing us to set expectations on inputs.
+ * One thing to note is the use of overloaded AND/OR operators.
+ *
+ * Concern: One thing I didn't understand was that in the book "The Art of Unit Testing"
+ * the author would instantiate new instances of input in both the expectation and invokation, making them
+ * different. From my expierence it seems like you need to expect a specific instance. If a different
+ * instance is recieved in the invokation step the test will fail. Does this mean I have to inject my input
+ * as well as my Writer? For primitive types this wasn't the case.
+ *
+ * UPDATE: Now it works like in the book ... (Try and replicate error)
+ */
+
+ [Test]
+ public void RhinoMock_SetMonthsUsingWriterInput_Proper_Content_Sent()
+ {
+ IWriter Writer = _Mocks.DynamicMock();
+ _ObjUtilTestable._Writer = Writer;
+
+ using (_Mocks.Record())
+ {
+ Writer.ValidateAndWrite(new WriterInput("emptyFile.txt", _ExpectedMonthsAsString));
+ LastCall.Constraints(
+ Property.Value("Path", "emptyFile.txt")
+ && Property.Value("Content", _ExpectedMonthsAsString)
+ ).Return(true);
+ }
+
+ _ObjUtilTestable.SetMonthsUsingWriterInput("emptyFile.txt");
+ _Mocks.VerifyAll();
+ }
+
+ /* DELEGATES
+ *
+ * //// MISSING EXAMPLE ////
+ *
+ * Concern: I noticed that certain features are missing, I don't know if it's a version issue
+ * but my version of Rhino mock doesn't seem to have Is.Matching, So I couldn't introduce test code for delegates.
+ */
+
+
+ /* AAA (ARRANGE, ACT, ASSERT)
+ *
+ * It maybe more intutive to design tests according to AAA rather than Record and Replay, which is what the above tests were
+ * using. Instead of setting expectations ahead of actually running our testable code we simply setup our test objects,
+ * run the code, and then assert that the stuff we expected to happen ... happened. This way of formating tests also requires
+ * the use of the lambda feature in C# so be wary if you aren't comfortable with functional language principles specifically
+ * how to use anonymous functions.
+ */
+ [Test]
+ public void RhinoMock_SetMonths_Proper_Content_Sent_AAA()
+ {
+ // Arrange
+ IWriter Writer = _Mocks.DynamicMock();
+ _ObjUtilTestable._Writer = Writer;
+
+ // Act
+ _Mocks.ReplayAll();
+ _ObjUtilTestable.SetMonths("emptyFile.txt");
+
+ // Assert
+ Writer.AssertWasCalled
+ (writer => writer.ValidateAndWrite
+ ("emptyFile.txt",_ExpectedMonthsAsString));
+ }
+
+ [Test]
+ public void RhinoMock_GetMonths_Returns_All_Months_AAA()
+ {
+ // Arrange
+ IReader Reader = _Mocks.Stub();
+ _ObjUtilTestable._Reader = Reader;
+
+ Reader.Expect(reader => reader.ValidateAndRead("file.txt")).Return(_ExpectedMonthsAsString);
+
+ // Act
+ _Mocks.ReplayAll();
+ string[] Result = _ObjUtilTestable.GetMonthsStubUsingLocalFactory();
+
+ // Assert
+ Assert.AreEqual(_ExpectedMonths, Result);
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ _ObjUtil = null;
+ _Reader = null;
+ }
+ }
+}
diff --git a/BasicApp.Test/packages.config b/BasicApp.Test/packages.config
new file mode 100644
index 0000000..219b8d8
--- /dev/null
+++ b/BasicApp.Test/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file