1_
How to expose assembly internals for testing
Add following line into AssemblyInfo.cs of the assembly which internals should be exposed
C# [assembly: InternalsVisibleTo ("MyTestAssemblyName")]
2_
How to access private methods and members in unit tests
Assuming having a class like this:
The way how it is possible to work around is to use PrivateObject class . Note: This is not available in Visual Studio express.
C# class ClassToBeTested { private bool Test() { return true; } private int Add(int a, int b) { return a+b; } private int IntField; private int IntProperty { get; set; } }Visual Studio 2010 provided the option to create so callled accessor . This feature is not available if newer versions.
The way how it is possible to work around is to use PrivateObject class . Note: This is not available in Visual Studio express.
C# using Microsoft.VisualStudio.TestTools.UnitTesting; // Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll ... ClassToBeTested target = new ClassToBeTested(); PrivateObject privObj = new PrivateObject(target); var retValue = obj.Invoke("Test"); object[] args1 = { 1, 2 }; retValue = obj.Invoke("Add", args1); obj.SetField("IntField", 1); retValue = obj.GetField("IntField"); obj.SetProperty("IntProperty", 2); retValue = obj.GetProperty("IntProperty");
3_
How to create object with private constructor
Sometimes objects like exceptions may have private constructors. If it is necessary to create such an object e.g. for testing,
it is possible to create it in following way:
C# private OracleException CreateOracleException(string message) { ConstructorInfo ci = typeof(OracleException).GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(int) }, null); return (OracleException)ci.Invoke(new object[] { "my message", 123 }); }
4_
How to get test coverage for NUnit tests
1. Install OpenCover NuGet package 2. Install NUnit.Runners NuGet package (skip for MSTest) 3. Install ReportGenarator NuGet package 4. Create the batch below under output folder where MyTest.dll is located :: run MSTest (MStest only) "..\..\packages\OpenCover.4.6.519\tools\OpenCover.Console.exe" -target:"c:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\MSTest.exe" -targetargs:"/testcontainer:<my drop path>\myTest.dll" /noshadow" -register:user -output:myCoverage.xmly :: run NUnit (NUnit only) "..\..\packages\OpenCover.4.6.519\tools\OpenCover.Console.exe" -target:"..\..\packages\NUnit.Runners.Net4.2.6.4\tools\nunit-console.exe" -targetargs:"/nologo myTest.dll /noshadow" -register:user -output:"myCoverage.xmly" :: generate reports "..\..\packages\ReportGenerator.2.4.5.0\tools\ReportGenerator.exe" "-reports:myCoverage.xmly" "-targetdir:MyTest" start MyTest\index.htm
5_
Implement test method that tests PersonManager.GetCalculatedPerson(int id) method and mocks database call with Fakes
Imagine you need to write a code
The method name gets generated based on the pattern MethodName+ArgumentName
By default the fake implementation throws NotImplementedException.
C# namespace FakesBasics { public class Person { public int Id; public string FirstName; public string LastName; public string FullName; } public interface IDataProvider { Person GetPerson(int id); } public class DataProvider : IDataProvider { public Person GetPerson(int id) { Person person = new Person(); // connect to database and populate static person data throw new NotImplementedException(); // return person; unreachable code now, will be implemented in real world } } public class PersonManager { IDataProvider _dataProvider; public PersonManager(IDataProvider dataProvider) { _dataProvider = dataProvider; } public Person GetCalculatedPerson(int id) { // read form database Person person = _dataProvider.GetPerson(id); // calculate fields that change person.FullName = person.FirstName + " " + person.LastName; return person; } } }
3. in the references list in FakesBasics.Test project right click and select "Add Fakes assembly" => FakesBasics.Fakes will be added to the listWhen you add Fakes assembly, a code in namespace CurrentNamespace.Fakes.StubClassName gets generated. The faked class has all the methods as the original class and the behavior of the methods in the fake class can be replaced.
The method name gets generated based on the pattern MethodName+ArgumentName
By default the fake implementation throws NotImplementedException.
C# [TestMethod] public void WhenGetCalucatedPersonIsCalled_ThenFullNameIsCalculated() { // arrange int age = 26; DateTime birthDay = DateTime.Now.AddYears(age); IDataProvider fakeProvider = new FakesBasics.Fakes.StubIDataProvider() { GetPersonInt32 = (id) => { return new Person() { Id = id, FirstName = "John", LastName = "First" }; } }; PersonManager pm = new PersonManager(fakeProvider); // act Person p = pm.GetCalculatedPerson(1); // assert Assert.AreEqual("John First", p.FullName); }
7_
Write a test that expects exception in NUnit
NUnit - Assert.Throws
C# [Test] public void When_ExpectedExceptionIsThrownAndAssertThrowsIsUsed_Then_TestPasses() { NUnit.Framework.Assert.Throws(typeof(ArgumentException), delegate { MyProduct.MethodThatThrows(1); }); NUnit.Framework.Assert.Throws<ArgumentException>(delegate { MyProduct.MethodThatThrows(1); }); } [Test] // [NUnit.Framework.ExpectedException(typeof(ArgumentException))] Deprecated in NUnit 3 public void When_ExpectedExceptionIsThrownAndAttributeIsUsed_Then_TestPasses() { MyProduct.MethodThatThrows(1); }
8_
Write a test method that tests various test conditions (for one method) in NUnit
When using [TestCase] instead of [Test], NUnit will run 3 tests for the example below
C# [TestCase("abc", 1)] [TestCase("abc", 2)] [TestCase("", 1)] public void DemoTestKace(string arg1, int arg2) { // test code - arg1 and arg2 are populate with the values in [TestCase(..)] }