Wednesday, August 2, 2017

Popular Unit Test Naming Conventions

  1. MethodName_StateUnderTest_ExpectedBehavior: There are arguments against this strategy that if method names change as part of code refactoring than test name like this should also change or it becomes difficult to comprehend at a later stage. Following are some of the example:
    • isAdult_AgeLessThan18_False
    • withdrawMoney_InvalidAccount_ExceptionThrown
    • admitStudent_MissingMandatoryFields_FailToAdmit
  2. MethodName_ExpectedBehavior_StateUnderTest: Slightly tweeked from above, but a section of developers also recommend using this naming technique. This technique also has disadvantage that if method names get changed, it becomes difficult to comprehend at a later stage. Following is how tests in first example would read like if named using this technique:
    • isAdult_False_AgeLessThan18
    • withdrawMoney_ThrowsException_IfAccountIsInvalid
    • admitStudent_FailToAdmit_IfMandatoryFieldsAreMissing
  3. test[Feature being tested]: This one makes it easy to read the test as the feature to be tested is written as part of test name. Although, there are arguments that the “test” prefix is redundant. However, some sections of developer love to use this technique. Following is how the above tests would read like if named using this technique:
    • testIsNotAnAdultIfAgeLessThan18
    • testFailToWithdrawMoneyIfAccountIsInvalid
    • testStudentIsNotAdmittedIfMandatoryFieldsAreMissing
  4. Feature to be tested: Many suggests that it is better to simply write the feature to be tested because one is anyway using annotations to identify method as test methods. It is also recommended for the reason that it makes unit tests as alternate form of documentation and avoid code smells. Following is how tests in first example would read like if named using this technique:
    • IsNotAnAdultIfAgeLessThan18
    • FailToWithdrawMoneyIfAccountIsInvalid
    • StudentIsNotAdmittedIfMandatoryFieldsAreMissing
  5. Should_ExpectedBehavior_When_StateUnderTest: This technique is also used by many as it makes it easy to read the tests. Following is how tests in first example would read like if named using this technique:
    • Should_ThrowException_When_AgeLessThan18
    • Should_FailToWithdrawMoney_ForInvalidAccount
    • Should_FailToAdmit_IfMandatoryFieldsAreMissing
  6. When_StateUnderTest_Expect_ExpectedBehavior: Following is how tests in first example would read like if named using this technique:
    • When_AgeLessThan18_Expect_isAdultAsFalse
    • When_InvalidAccount_Expect_WithdrawMoneyToFail
    • When_MandatoryFieldsAreMissing_Expect_StudentAdmissionToFail
  7. Given_Preconditions_When_StateUnderTest_Then_ExpectedBehavior: This approach is based on naming convention developed as part of Behavior-Driven Development (BDD). The idea is to break down the tests into three part such that one could come up with preconditions, state under test and expected behavior to be written in above format. Following is how tests in first example would read like if named using this technique:
    • Given_UserIsAuthenticated_When_InvalidAccountNumberIsUsedToWithdrawMoney_Then_TransactionsWillFail
-------------------------------------------------------------------------------------------------------------------------------------------


.runsettings and .testsettings

There are two types of file for configuring tests. *.runsettings are used for unit tests.
 And *.testsettings for lab environment tests, web performance and load tests, and for customizing some types of diagnostic data adapters such as Intellitrace and event log adapters.
---------------------Example-----------------------------------------------------------------------------------------------------

[TestMethod(), TestCategory("Web")]

        public async Task IndexTest_When_PageLoadWithGridData_Then_ReturnData()

        {



             //Arrange
            var loggerMock = new Mock<ILogManager>();
            loggerMock.Setup(l => l.Log(It.IsAny<LogEntry>()));

            var exceptionLogMock = new Mock<IExceptionLog>();
            exceptionLogMock.Setup(a => a.WriteExceptionToEventLog(It.IsAny<string>(), EventLogEntryType.Error, It.IsAny<string>(), It.IsAny<string>()));

            var pagedProductModel = new PagedProductModel { TotalNoOfRecords = 10, CurrentPage = 1, PageSize = 10, Search = "", SortBy = 1, IsAsc = true, Products = new List<ProductModel> { new ProductModel { ProductId = 1, ProductName = "subrat", UnitPrice = 435 }, new ProductModel { ProductId = 2, ProductName = "subrat", UnitPrice = 435 }, new ProductModel { ProductId = 3, ProductName = "subrat", UnitPrice = 435 } } };

            var productApiServiceMock = new Mock<ProductApiServiceBase>();
            productApiServiceMock.Setup(ps => ps.GetData(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<string>()))
                .Returns(async () => { return await Task.FromResult(pagedProductModel); });

            var requestMock = new Mock<HttpRequestBase>();
            var contextMock = new Mock<HttpContextBase>();
            contextMock.SetupGet(x => x.Request).Returns(requestMock.Object);

            ProductApiController productApiController = new ProductApiController(loggerMock.Object, exceptionLogMock.Object, productApiServiceMock.Object);
            productApiController.ControllerContext = new ControllerContext(contextMock.Object, new RouteData(), new Mock<ControllerBase>().Object);
            //Act
            var response = await productApiController.Index(10, 1, 1, true, "");
            //Assert
            Assert.IsNotNull(response);
            Assert.IsInstanceOfType(response, typeof(ViewResult));
            var model = (PagedProductModel)((ViewResult)response).Model;
            Assert.AreEqual(true, model.TotalNoOfRecords >= 0);
            //Assert.AreEqual(response.StatusCode, System.Net.HttpStatusCode.OK);
            //loggerMock.VerifyAll();
           // exceptionLogMock.VerifyAll();
            productApiServiceMock.VerifyAll();

            //    throw new NotImplementedException();



            // Assert

            //Assert.IsNotNull(result);
            //Assert.IsNotNull(result.Model); // add additional checks on the Model
            //Assert.IsTrue(string.IsNullOrEmpty(result.ViewName) || result.ViewName == "Index");
        }

        [TestMethod()]
        public async Task IndexTest_When_PageLoadWithGridDataWithAjaxCall_Then_ReturnData()
        {
            var logger = new Mock<ILogManager>();
            logger.Setup(l => l.Log(It.IsAny<Core.Logging.LogEntry>()));

            var exceptionLog = new Mock<IExceptionLog>();
            exceptionLog.Setup(a => a.WriteExceptionToEventLog(It.IsAny<string>(), EventLogEntryType.Error, "SubProjWeb", "SubProjWeb"));

            var productApiService = new Mock<ProductApiServiceBase>();
            var db = new PagedProductModel();
            var products = new List<ProductModel>();
            products.Add(new ProductModel { ProductId = 1, ProductName = "subrat", UnitPrice = 435 });
            products.Add(new ProductModel { ProductId = 1, ProductName = "samal", UnitPrice = 435 });
            db = new PagedProductModel { TotalNoOfRecords = 10, CurrentPage = 1, PageSize = 10, Search = "", SortBy = 1, IsAsc = true, Products = products };

            productApiService.Setup(sb => sb.GetData(10, 1, 1, true, ""))
                .Returns(async () => { return await Task.FromResult(db); });

            var request = new Mock<HttpRequestBase>();
            request.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection { { "X-Requested-With", "XMLHttpRequest" } });
            var context = new Mock<HttpContextBase>();
            context.SetupGet(x => x.Request).Returns(request.Object);

            ProductApiController pac = new ProductApiController(logger.Object, exceptionLog.Object, productApiService.Object);
            pac.ControllerContext = new ControllerContext(context.Object, new RouteData(), pac);

            var result = await pac.Index(10, 1, 1, true, "") as PartialViewResult;
            Assert.IsNotNull(result);
            var model = (PagedProductModel)((PartialViewResult)result).Model;
            Assert.AreEqual(true, model.TotalNoOfRecords >= 0);
            productApiService.VerifyAll();
        }

        [TestMethod()]
        [ExpectedException(typeof(Exception))]
        public async Task IndexTest_When_PageLoadWithGridDataException_Then_ReturnException()
        {
            //  var auditManager = new Mock<IAuditManager>();
            //auditManager.Setup(a => a.Log(It.IsAny<string>()));

            var logger = new Mock<ILogManager>();
            logger.Setup(l => l.Log(It.IsAny<Core.Logging.LogEntry>()));

            var exceptionLog = new Mock<IExceptionLog>();
            exceptionLog.Setup(a => a.WriteExceptionToEventLog(It.IsAny<string>(), EventLogEntryType.Error, "SubProjWeb", "SubProjWeb"));

            var productApiService = new Mock<ProductApiServiceBase>();
            //productApiService.Setup(sb => sb.GetData(10, 1, 1, true, ""))
                          .Throws<Exception>();
 productApiService.Setup(sb => sb.GetData(10, 1, 1, true, ""))
                          .Throws(new Exception());

            var request = new Mock<HttpRequestBase>();
            var context = new Mock<HttpContextBase>();
            context.SetupGet(x => x.Request).Returns(request.Object);

            ProductApiController pac = new ProductApiController(logger.Object, exceptionLog.Object, productApiService.Object);
            pac.ControllerContext = new ControllerContext(context.Object, new RouteData(), pac);

            var result = await pac.Index(10, 1, 1, true, "") as ViewResult;
        }


----------------------------------------------------Entity class unit testing-------------------------------------------------------
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace BSS.SubProj.Entities.Tests
{
    [TestClass()]
    public class ProductTests
    {
        [TestMethod]
        public void Product_Properties_StoresCorrectly()
        {
            var sut = new Product
            {
                ProductId = 1,
                ProductName = "Test",
                UnitPrice = 1
            };
            Assert.AreEqual(1, sut.ProductId, "Oops...");
            Assert.AreEqual("Test", sut.ProductName, "Oops...");
            Assert.AreEqual(1, sut.UnitPrice, "Oops...");
        }
    }
}

--------------------------------------------------------------------------------------------------------------------------------------------

MSTest v2: Data tests


[TestClass] public class MathTests { [DataTestMethod] [DataRow(1, 1, 2)] [DataRow(12, 30, 42)] [DataRow(14, 1, 15)] public void Test_Add(int a, int b, int expected) { var actual = MathHelper.Add(a, b); Assert.AreEqual(expected, actual); } }


Example with a method:
[TestClass]
public class MathTests
{
    [DataTestMethod]
    [DynamicData(nameof(GetData), DynamicDataSourceType.Method)]
    public void Test_Add_DynamicData_Method(int a, int b, int expected)
    {
        var actual = MathHelper.Add(a, b);
        Assert.AreEqual(expected, actual);
    }

    public static IEnumerable<object[]> GetData()
    {
        yield return new object[] { 1, 1, 2 };
        yield return new object[] { 12, 30, 42 };
        yield return new object[] { 14, 1, 15 };
    }
}
Example with a property:

[TestClass]
public class MathTests
{
    [DataTestMethod]
    [DynamicData(nameof(Data), DynamicDataSourceType.Property)]
    public void Test_Add_DynamicData_Property(int a, int b, int expected)
    {
        var actual = MathHelper.Add(a, b);
        Assert.AreEqual(expected, actual);
    }

    public static IEnumerable<object[]> Data
    {
        get
        {
            yield return new object[] { 1, 1, 2 };
            yield return new object[] { 12, 30, 42 };
            yield return new object[] { 14, 1, 15 };
        }
    }
}

#Custom DataSource

public class CustomDataSourceAttribute : Attribute, ITestDataSource { public IEnumerable<object[]> GetData(MethodInfo methodInfo) { yield return new object[] { 1, 1, 2 }; yield return new object[] { 12, 30, 42 }; yield return new object[] { 14, 1, 15 }; } public string GetDisplayName(MethodInfo methodInfo, object[] data) { if (data != null) return string.Format(CultureInfo.CurrentCulture, "Custom - {0} ({1})", methodInfo.Name, string.Join(",", data)); return null; } }

[DataTestMethod] [CustomDataSource] public void Test_Add(int a, int b, int expected) { var actual = MathHelper.Add(a, b); Assert.AreEqual(expected, actual); }
---------------------------------------------------------------------------------------------------------------------------------------------
MOQ
------

Moq is intended to be simple to use, strongly typed (no magic strings!, and therefore full compiler-verified and refactoring-friendly) and minimalistic (while still fully functional!).

Methods

using Moq;

// Assumptions:

public interface IFoo
{
    Bar Bar { get; set; }
    string Name { get; set; }
    int Value { get; set; }
    bool DoSomething(string value);
    bool DoSomething(int number, string value);
    string DoSomethingStringy(string value);
    bool TryParse(string value, out string outputValue);
    bool Submit(ref Bar bar);
    int GetCount();
    bool Add(int value);
}

public class Bar 
{
    public virtual Baz Baz { get; set; }
    public virtual bool Submit() { return false; }
}

public class Baz
{
    public virtual string Name { get; set; }
}


var mock = new Mock<IFoo>();
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);


// out arguments
var outString = "ack";
// TryParse will return true, and the out argument will return "ack", lazy evaluated
mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);


// ref arguments
var instance = new Bar();
// Only matches if the ref argument to the invocation is the same instance
mock.Setup(foo => foo.Submit(ref instance)).Returns(true);


// access invocation arguments when returning a value
mock.Setup(x => x.DoSomethingStringy(It.IsAny<string>()))
  .Returns((string s) => s.ToLower());
// Multiple parameters overloads available


// throwing when invoked with specific parameters
mock.Setup(foo => foo.DoSomething("reset")).Throws<InvalidOperationException>();
mock.Setup(foo => foo.DoSomething("")).Throws(new ArgumentException("command"));


// lazy evaluating return value
var count = 1;
mock.Setup(foo => foo.GetCount()).Returns(() => count);


// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCount())
 .Returns(() => calls)
 .Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCount());

Matching Arguments

// any value
mock.Setup(foo => foo.DoSomething(It.IsAny<string>())).Returns(true);


// matching Func<int>, lazy evaluated
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true); 


// matching ranges
mock.Setup(foo => foo.Add(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns(true); 


// matching regex
mock.Setup(x => x.DoSomethingStringy(It.IsRegex("[a-d]+", RegexOptions.IgnoreCase))).Returns("foo");

Properties

mock.Setup(foo => foo.Name).Returns("bar");


// auto-mocking hierarchies (a.k.a. recursive mocks)
mock.Setup(foo => foo.Bar.Baz.Name).Returns("baz");

// expects an invocation to set the value to "foo"
mock.SetupSet(foo => foo.Name = "foo");

// or verify the setter directly
mock.VerifySet(foo => foo.Name = "foo");
  • Setup a property so that it will automatically start tracking its value (also known as Stub):
// start "tracking" sets/gets to this property
mock.SetupProperty(f => f.Name);

// alternatively, provide a default value for the stubbed property
mock.SetupProperty(f => f.Name, "foo");


// Now you can do:

IFoo foo = mock.Object;
// Initial value was stored
Assert.Equal("foo", foo.Name);

// New value set which changes the initial value
foo.Name = "bar";
Assert.Equal("bar", foo.Name);
  • Stub all properties on a mock (not available on Silverlight):
mock.SetupAllProperties();

Events

// Raising an event on the mock
mock.Raise(m => m.FooEvent += null, new FooEventArgs(fooValue));

// Raising an event on a descendant down the hierarchy
mock.Raise(m => m.Child.First.FooEvent += null, new FooEventArgs(fooValue));

// Causing an event to raise automatically when Submit is invoked
mock.Setup(foo => foo.Submit()).Raises(f => f.Sent += null, EventArgs.Empty);
// The raised event would trigger behavior on the object under test, which 
// you would make assertions about later (how its state changed as a consequence, typically)

// Raising a custom event which does not adhere to the EventHandler pattern
public delegate void MyEventHandler(int i, bool b);
public interface IFoo
{
  event MyEventHandler MyEvent; 
}

var mock = new Mock<IFoo>();
...
// Raise passing the custom arguments expected by the event delegate
mock.Raise(foo => foo.MyEvent += null, 25, true);

Callbacks

var mock = new Mock<IFoo>();
var calls = 0;
var callArgs = new List<string>();

mock.Setup(foo => foo.DoSomething("ping"))
 .Returns(true)
 .Callback(() => calls++);

// access invocation arguments
mock.Setup(foo => foo.DoSomething(It.IsAny<string>()))
 .Returns(true)
 .Callback((string s) => callArgs.Add(s));

// alternate equivalent generic method syntax
mock.Setup(foo => foo.DoSomething(It.IsAny<string>()))
 .Returns(true)
 .Callback<string>(s => callArgs.Add(s));

// access arguments for methods with multiple parameters
mock.Setup(foo => foo.DoSomething(It.IsAny<int>(), It.IsAny<string>()))
 .Returns(true)
 .Callback<int, string>((i, s) => callArgs.Add(s));

// callbacks can be specified before and after invocation
mock.Setup(foo => foo.DoSomething("ping"))
 .Callback(() => Console.WriteLine("Before returns"))
 .Returns(true)
 .Callback(() => Console.WriteLine("After returns"));

Verification

mock.Verify(foo => foo.DoSomething("ping"));

// Verify with custom error message for failure
mock.Verify(foo => foo.DoSomething("ping"), "When doing operation X, the service should be pinged always");

// Method should never be called
mock.Verify(foo => foo.DoSomething("ping"), Times.Never());

// Called at least once
mock.Verify(foo => foo.DoSomething("ping"), Times.AtLeastOnce());

// Verify getter invocation, regardless of value.
mock.VerifyGet(foo => foo.Name);

// Verify setter invocation, regardless of value.
mock.VerifySet(foo => foo.Name);

// Verify setter called with specific value
mock.VerifySet(foo => foo.Name ="foo");

// Verify setter with an argument matcher
mock.VerifySet(foo => foo.Value = It.IsInRange(1, 5, Range.Inclusive));

Customizing Mock Behavior

  • Make mock behave like a "true Mock", raising exceptions for anything that doesn't have a corresponding expectation: in Moq slang a "Strict" mock; default behavior is "Loose" mock, which never throws and returns default values or empty arrays, enumerables, etc. if no expectation is set for a member
    var mock = new Mock<IFoo>(MockBehavior.Strict);
  • Invoke base class implementation if no expectation overrides the member (a.k.a. "Partial Mocks" in Rhino Mocks): default is false. (this is required if you are mocking Web/Html controls in System.Web!)
    var mock = new Mock<IFoo> { CallBase = true };
  • Make an automatic recursive mock: a mock that will return a new mock for every member that doesn't have an expectation and whose return value can be mocked (i.e. it is not a value type)
    var mock = new Mock<IFoo> { DefaultValue = DefaultValue.Mock };
    // default is DefaultValue.Empty
    
    // this property access would return a new mock of Bar as it's "mock-able"
    Bar value = mock.Object.Bar;
    
    // the returned mock is reused, so further accesses to the property return 
    // the same mock instance. this allows us to also use this instance to 
    // set further expectations on it if we want
    var barMock = Mock.Get(value);
    barMock.Setup(b => b.Submit()).Returns(true);
  • Centralizing mock instance creation and management: you can create and verify all mocks in a single place by using a MockRepository, which allows setting the MockBehavior, its CallBase and DefaultValue consistently
    var repository = new MockRepository(MockBehavior.Strict) { DefaultValue = DefaultValue.Mock };
    
    // Create a mock using the repository settings
    var fooMock = repository.Create<IFoo>();
    
    // Create a mock overriding the repository settings
    var barMock = repository.Create<Bar>(MockBehavior.Loose);
    
    // Verify all verifiable expectations on all mocks created through the repository
    repository.Verify();

Miscellaneous

  • Setting up a member to return different values / throw exceptions on sequential calls:
    var mock = new Mock<IFoo>();
    mock.SetupSequence(f => f.GetCount())
        .Returns(3)  // will be returned on 1st invocation
        .Returns(2)  // will be returned on 2nd invocation
        .Returns(1)  // will be returned on 3rd invocation
        .Returns(0)  // will be returned on 4th invocation
        .Throws(new InvalidOperationException());  // will be thrown on 5th invocation
  • Setting expectations for protected members (you can't get intellisense for these, so you access them using the member name as a string):
    // at the top of the test fixture
    using Moq.Protected;
    
    // in the test
    var mock = new Mock<CommandBase>();
    mock.Protected()
         .Setup<int>("Execute")
         .Returns(5);
    
    // if you need argument matching, you MUST use ItExpr rather than It
    // planning on improving this for vNext
    mock.Protected()
        .Setup<string>("Execute",
            ItExpr.IsAny<string>())
        .Returns(true);

Advanced Features

// get mock from a mocked instance
IFoo foo = // get mock instance somehow
var fooMock = Mock.Get(foo);
fooMock.Setup(f => f.GetCount()).Returns(42);


// implementing multiple interfaces in mock
var mock = new Mock<IFoo>();
var disposableFoo = mock.As<IDisposable>();
// now the IFoo mock also implements IDisposable :)
disposableFoo.Setup(disposable => disposable.Dispose());

// implementing multiple interfaces in single mock
var mock = new Mock<IFoo>();
mock.Setup(foo => foo.Name).Returns("Fred");
mock.As<IDisposable>().Setup(disposable => disposable.Dispose());


// custom matchers
mock.Setup(foo => foo.DoSomething(IsLarge())).Throws<ArgumentException>();
...
public string IsLarge() 
{ 
  return Match.Create<string>(s => !String.IsNullOrEmpty(s) && s.Length > 100);
}
  • Mocking internal types of another project: add the following assembly attribute (typically to the AssemblyInfo.cs) to the project containing the internal types:
    // This assembly is the default dynamic assembly generated Castle DynamicProxy, 
    // used by Moq. Paste in a single line. 
    [assembly:InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

Note: When you pass the mock for consumption, you must pass mock.Object, not mock itself.

Linq to Mocks

Moq is the one and only mocking framework that allows specifying mock behavior via declarative specification queries. You can think of Linq to Mocks as:
from the universe of mocks, get me one/those that behave like this (by Fernando Simonazzi)
Keep that query form in mind when reading the specifications:
var services = Mock.Of<IServiceProvider>(sp =>
    sp.GetService(typeof(IRepository)) == Mock.Of<IRepository>(r => r.IsAuthenticated == true) &&
    sp.GetService(typeof(IAuthentication)) == Mock.Of<IAuthentication>(a => a.AuthenticationType == "OAuth"));

// Multiple setups on a single mock and its recursive mocks
ControllerContext context = Mock.Of<ControllerContext>(ctx =>
     ctx.HttpContext.User.Identity.Name == "kzu" &&
     ctx.HttpContext.Request.IsAuthenticated == true &&
     ctx.HttpContext.Request.Url == new Uri("http://moqthis.com") &&
     ctx.HttpContext.Response.ContentType == "application/xml");

// Setting up multiple chained mocks:
var context = Mock.Of<ControllerContext>(ctx =>
     ctx.HttpContext.Request.Url == new Uri("http://moqthis.me") &&
     ctx.HttpContext.Response.ContentType == "application/xml" &&
     // Chained mock specification
     ctx.HttpContext.GetSection("server") == Mock.Of<ServerSection>(config =>
         config.Server.ServerUrl == new Uri("http://moqthis.com/api"));
Linq to Mocks is great for quickly stubbing out dependencies that typically don't need further verification. If you do need to verify later some invocation on those mocks, you can easily retrieve them with Mock.Get(instance).

No comments:

Post a Comment

Encrypt/Decrypt the App.Config

Program.cs using System; using System.Diagnostics; using System.IO; namespace EncryptAppConfig {     internal class Program     {         pr...