Showing posts with label Mocking. Show all posts
Showing posts with label Mocking. Show all posts

Thursday, November 28, 2013

Testing un-mockable base class methods

Working on a project using the Xamarin Framework and came across a problem where I needed to see if a method was being called.  The problem was the method was on the base class and was un-mockable

To get around this I used a lazy load property and a delegate to create a wrapper.
   1: private StartActivityDelegate _start;
   2: public StartActivityDelegate Start
   3: {
   4:     get { return _start ?? (_start = StartActivity); }
   5:     set { _start = value; }
   6: }
   7:  
   8: public delegate void StartActivityDelegate (Type type);
   9:  
  10: protected override void OnCreate(Bundle bundle)
  11: {
  12:     base.OnCreate(bundle);
  13:     Redirect();
  14: }
  15:  
  16: public void Redirect()
  17: {
  18:     if (Preferences.HasRequired())
  19:     {
  20:         Start(typeof(ClientActivity));
  21:     }
  22:     else
  23:     {
  24:         Start(typeof(SettingsActivity));
  25:     }   
  26: }
To test it you simply set the property in my test class to a test method
   1: [TestFixture]
   2: public class When_Starting_SplashScreen_Without_Required_Preferences_Test
   3: {
   4:     public SplashActivity Target;
   5:     public Type Actual;
   6:     public PreferencesMock PreferencesMock;
   7:  
   8:     public void TestStartActivity(Type type)
   9:     {
  10:         Actual = type;
  11:     }
  12:  
  13:     [SetUp]
  14:     public void SetUp()
  15:     {
  16:         PreferencesMock = new PreferencesMock { HasRequiredStub = false };
  17:  
  18:         Target = new SplashActivity { Start = TestStartActivity, Preferences = PreferencesMock };
  19:         Target.Redirect();
  20:     }
  21:  
  22:     [Test]
  23:     public void Has_Expected_Activity_Test()
  24:     {
  25:         Assert.AreEqual(typeof(SettingsActivity), Actual);
  26:     }
  27: }
Next to test that we are calling the base class method we are expecting, we add a new test fixture and use a little reflection to get the method info for each and then compare them
   1: [TestFixture]
   2: public class SplashActivity_Tests
   3: {
   4:     public SplashActivity Target;
   5:     
   6:     [SetUp]
   7:     public void SetUp()
   8:     {
   9:         Target = new SplashActivity();            
  10:     }
  11:  
  12:     [Test]
  13:     public void LazyLoads_Write_Test()
  14:     {
  15:         MethodInfo actual = Target.Start.GetMethodInfo();
  16:         MethodInfo expected = typeof(Activity).GetMethod("StartActivity");
  17:         Assert.AreSame(expected, actual);
  18:     }      
  19: }

Tuesday, January 8, 2013

Tools only give you the ability

Recently I read a post on the Alt.net linked-in group Would mocking help prevent these software bugs? talking about the Knight Capital Group Inc.’s disaster, asking the question "if doing more testing and using mocks would have prevented it?"

Doing unit testing with mocking is a tool, not a silver bullet. Unit tests mixed with behavior testing can be very effective at finding these kinds of bugs and Mocks allow you to create and test against foreseen conditions.  While TDD can help expose bugs, unforeseen data conditions can pass though unnoticed, tests only test what they are told to.

Something else to keep in mind is behavior and unit tests are only a small part of the testing tool box that also includes: integration tests, performance tests, automated UI tests, etc.  and that’s what these are tools.  How effective they are depends on the user, a funny quote I once heard is “A tool runs tools, a craftsman uses them”.  You can run your code coverage tool all day long and say “look I have 80% code coverage” but this doesn't mean your code is well tested, it just means it has test that run though it, and can hide untested code. 

One commenter on the article said something to the effect that what they where working on requires to much performance to be testable.   I would like to state this is B.S. you can make testable code that has just as much performance as not testable code. You may have to change how you test the code, or use different design or testing techniques for example Dependency Injection isn't required to make testable code, if it's not fast enough use greedy constructors or lazy load properties. If you need to make a black box class for performance, you simply do integration tests around it.

In the end, saying TDD isn’t of value because it didn’t catch bug xyz is like a carpenter blaming his hammer for hitting his thumb and not the nail.  On the other side it’s just as ridiculous to say “I can build a house” simply because you own a hammer and some nails.

Monday, June 25, 2012

Testing for execution sequence

I ran into a problem the other day where I was doing some cost calculations and wasn’t getting the expected result, the problem turned out to be I was doing the calculations before everything got loaded, simple mistake.

Thought it would be interesting to show the solution I used for testing, lets say we have a simple method for updating an employee record.
   1: public bool UpdateEmployee(EmployeeDto updateEmployee)
   2: {
   3:     var result = false;
   4:     if(AuthRequests.UserCanUpdateEmployee(User.Id,updateEmployee.Id))
   5:     {
   6:         result = EmployeeRepository.UpdateEmployee(updateEmployee);
   7:     }
   8:     return result;
   9: }
fairly simple, you call AuthRequests to see if the user and update the employee and then you update the employee.  Here is an example test class for it
   1: [TestFixture]
   2: public class When_Updating_Employee_Information_Test: Test_Context<EmployeeRequests>
   3: {
   4:     public Mock<IAuthRequests> AuthRequestsMock;
   5:     public bool ExpectedAuth;
   6:     public int UserId;
   7:     public int EmployeeId;
   8:     public bool Actual;
   9:     public bool Expected;
  10:     public EmployeeDto UpdateEmployee;
  11:     public EmployeeDto SentEmployee;
  12:     public UserDto ExpectedUser;
  13:     public Mock<IEmployeeRepository> MockEmployeeRepository;
  14:  
  15:     public override void Context()
  16:     {
  17:         base.Context();
  18:         UserId = 12;
  19:         EmployeeId = 14;
  20:         Expected = true;
  21:         ExpectedAuth = true;
  22:         UpdateEmployee = new EmployeeDto{Id = EmployeeId};
  23:         Target.User.Id = UserId;
  24:         AuthRequestsMock = new Mock<IAuthRequests>();
  25:         MockEmployeeRepository = new Mock<IEmployeeRepository>();
  26:         
  27:         AuthRequestsMock.Setup(x => x.UserCanUpdateEmployee(UserId, EmployeeId)).Returns(ExpectedAuth);
  28:         MockEmployeeRepository.Setup(x => x.UpdateEmployee(It.IsAny<EmployeeDto>())).Callback<EmployeeDto>(
  29:             x => SentEmployee = x).Returns(Expected);
  30:  
  31:         Target.AuthRequests = AuthRequestsMock.Object;
  32:         Target.EmployeeRepository = MockEmployeeRepository.Object;
  33:     }
  34:  
  35:     public override void Because()
  36:     {
  37:         Actual = Target.UpdateEmployee(UpdateEmployee);
  38:     }
  39:  
  40:     [Test]
  41:     public void Calls_AuthRequests_UserCanUpdateEmployee_Test()
  42:     {
  43:         AuthRequestsMock.Verify(x=>x.UserCanUpdateEmployee(UserId, EmployeeId), Times.Once());
  44:     } 
  45:  
  46:     [Test]
  47:     public void Calls_EmployeeRepository_UpdateEmployee_Test()
  48:     {
  49:         MockEmployeeRepository.Verify(x => x.UpdateEmployee(It.IsAny<EmployeeDto>()), Times.Once());
  50:     }
  51:  
  52:     [Test]
  53:     public  void Sends_expected_Emplyee_test()
  54:     {
  55:         Assert.AreEqual(UpdateEmployee.Id, SentEmployee.Id);
  56:     }
  57:  
  58:     [Test]
  59:     public void Returns_Expected_Result_Test()
  60:     {
  61:         Assert.IsTrue(Actual);
  62:     }
  63: }
the only problem is the tests still pass if the method looks like this
   1: public bool UpdateEmployee(EmployeeDto updateEmployee)
   2: {
   3:     var result = EmployeeRepository.UpdateEmployee(updateEmployee);
   4:     AuthRequests.UserCanUpdateEmployee(User.Id,updateEmployee.Id);
   5:     return result;
   6: }
so lets add some sequence tests, basically we add a counter and a dictionary<string,int> to record what was executed and it what order using the Moq callback.
   1: [TestFixture]
   2: public class When_Updating_Employee_Information_With_sequence_Test : Test_Context<EmployeeRequests>
   3: {
   4:     public Mock<IAuthRequests> AuthRequestsMock;
   5:     public bool ExpectedAuth;
   6:     public int UserId;
   7:     public int EmployeeId;
   8:     public bool Actual;
   9:     public bool Expected;
  10:     public EmployeeDto UpdateEmployee;
  11:     public EmployeeDto SentEmployee;
  12:     public UserDto ExpectedUser;
  13:     public Mock<IEmployeeRepository> MockEmployeeRepository;
  14:     public int Counter;
  15:     public Dictionary<string, int> Sequence; 
  16:  
  17:     public override void Context()
  18:     {
  19:         base.Context();
  20:         UserId = 12;
  21:         EmployeeId = 14;
  22:         Expected = true;
  23:         ExpectedAuth = true;
  24:         UpdateEmployee = new EmployeeDto { Id = EmployeeId };
  25:         Counter = 0;
  26:         Sequence = new Dictionary<string, int>();
  27:         Target.User.Id = UserId;
  28:         AuthRequestsMock = new Mock<IAuthRequests>();
  29:         MockEmployeeRepository = new Mock<IEmployeeRepository>();
  30:  
  31:         AuthRequestsMock.Setup(x => x.UserCanUpdateEmployee(UserId, EmployeeId))
  32:             .Callback(() => Sequence.Add("AuthRequests.UserCanUpdateEmployee", Counter++)).Returns(ExpectedAuth);
  33:         MockEmployeeRepository.Setup(x => x.UpdateEmployee(It.IsAny<EmployeeDto>()))
  34:             .Callback<EmployeeDto>(x =>
  35:                  {
  36:                     SentEmployee = x;
  37:                     Sequence.Add("EmployeeRepository.UpdateEmployee", Counter++);
  38: }).Returns(Expected);
  39:  
  40:         Target.AuthRequests = AuthRequestsMock.Object;
  41:         Target.EmployeeRepository = MockEmployeeRepository.Object;
  42:     }
  43:  
  44:     public override void Because()
  45:     {
  46:         Actual = Target.UpdateEmployee(UpdateEmployee);
  47:     }
  48:  
  49:     [Test]
  50:     public void Calls_AuthRequests_UserCanUpdateEmployee_Test()
  51:     {
  52:         AuthRequestsMock.Verify(x => x.UserCanUpdateEmployee(UserId, EmployeeId), Times.Once());
  53:     }
  54:  
  55:     [Test]
  56:     public void Calls_AuthRequests_UserCanUpdateEmployee_Inorder_Test()
  57:     {
  58:         Assert.AreEqual(0, Sequence["AuthRequests.UserCanUpdateEmployee"]);
  59:     }
  60:  
  61:     [Test]
  62:     public void Calls_EmployeeRepository_UpdateEmployee_Test()
  63:     {
  64:         MockEmployeeRepository.Verify(x => x.UpdateEmployee(It.IsAny<EmployeeDto>()), Times.Once());
  65:     }
  66:  
  67:     [Test]
  68:     public void Calls_EmployeeRepository_UpdateEmployee_Inorder_Test()
  69:     {
  70:         Assert.AreEqual(1, Sequence["EmployeeRepository.UpdateEmployee"]);
  71:     }
  72:  
  73:     [Test]
  74:     public void Sends_expected_Emplyee_test()
  75:     {
  76:         Assert.AreEqual(UpdateEmployee.Id, SentEmployee.Id);
  77:     }
  78:  
  79:     [Test]
  80:     public void Returns_Expected_Result_Test()
  81:     {
  82:         Assert.IsTrue(Actual);
  83:     }
  84: }
for the full source see the sample application here.