Sunday, April 29, 2007

Testing Non-Public members with MbUnit (Part II).

Earlier this month I talked about how to test non-public members with MbUnit. Well there’s an interesting discussion on MbUnit group. As a result a new code was written.

Following methods are marked as obsolete. My guess is that these methods are going to be gone completely in version 3.

Old MethodNew Method
 GetNonPublicField  GetField 
 GetNonPublicVariable  GetField 
 GetNonPublicProperty  GetProperty 
 RunPrivateMethod  InvokeMethod 
 RunNonPublicMethod  InvokeMethod 


There're also new methods:
SetField - Sets field value.
SetProperty - Sets property value.

Thanks to Jeff who pointed out that Reflector didn’t have these methods. He also mentioned that method names between static and instance implementation are inconsistent. This also was corrected.

Let's create SampleClass:


public class SampleClass
{
  public string publicString = "MbUnit Rocks!!!";
  private DateTime privateDateTime = DateTime.Today;

  internal DateTime InternalProperty
  {
    get { return privateDateTime; }
    set { privateDateTime = value; }
  }

  private static int Add(int x, int y)
  {
    return x + y;
  }
}



Here an example how we can create tests for SampleClass:



TestSample _sampleObject;
Reflector _reflect;

[TestFixtureSetUp]
public void Init()
{
  _sampleObject = new SampleClass();
  _reflect = new Reflector(_sampleObject);
}

[Test]
public void GetPublicField()
{
  Assert.AreEqual("MbUnit Rocks!!!", _reflect.GetField("publicString"));
}

[Test]
public void SetNonPublicProperty()
{
  string propertyName = "InternalProperty";
  DateTime dt = new DateTime(2008, 1, 1);
  _reflect.SetProperty(propertyName, dt);
  Assert.AreEqual(dt, _reflect.GetProperty(propertyName));
}

[Test]
public void StaticPrivateMethod()
{
  Assert.AreEqual(7, _reflect.InvokeMethod("Add", 1, 6));
}



I mentioned before that static and instance methods now have consistent names.
You can implement StaticPrivateMethod test like this using static implementation of InvokeMethod(..).


[Test]
public void StaticPrivateMethod()
{
  Assert.AreEqual(7, Reflector.InvokeMethod(new SampleClass(), "Add", 1, 6));
}



Here's another of Jeff's suggestions:
Indicating public vs. non-public is useful for documentation purposes.


Once again, because of Jeff's suggestion we have AccessModifier enum type and using it we can specify if we want to access public, static, or non-public member. In examples above we didn't use AccessModifier. It means that Reflector will invoke method or access field or property as long as an object has implementation for it.

In the example below we are trying to test Add method that has private static modifier. However, if Add method wasn't static or was public, an assirtion would happen in our test.



[Test]
public void StaticPrivateMethod()
{
  Assert.AreEqual(7, _reflect.InvokeMethod(AccessModifier.Static | AccessModifier.NonPublic, , "Add", 1, 6));
}



It's a new code that was checked in; however, it has not been built yet. These and some other new features should be available in a next MbUnit build.

Thursday, April 12, 2007

Duration in MbUnit

Playing with MbUnit I just discovered DurationAttribute for the first time. This attribute sets the maximum time allowed for test to finish execution.

The test below will fail because in Duration attribute we set duration for one second but inside the test we sleep for 2 seconds.


[Test]
[Duration(1)]
public void DurationFailTest()
{
  Thread.Sleep(2000);
}


Next test will succeed because we don’t sleep at all.


[Test]
[Duration(1)]
public void DurationSuccessTest()
{
  Thread.Sleep(0);
}


You can use it with RowTest attribute. Row(0) will succeed and Row(2000) will obviously fail.


[RowTest, Duration(1)]
[Row(0)]
[Row(2000)]
public void DurationRowTest(int sleepTime)
{
  Thread.Sleep(sleepTime);
}

Tuesday, April 10, 2007

TypeMock too powerful to use

In my early stages of following TDD light I was looking for a mock object framework. I tried Rhino.Mocks and found it hard to use. Then I tried TypeMock and falled in love with the product. It allows mocking almost anything. With TypeMock I only failed to mock SqlDataReader because it doesn’t have a public constructor.

It was then. Today I believe that TypeMock is bad for the same reason I loved it before. It’s too powerful. It doesn’t force you to write a testable code.

The reason I found Rhino.Mocks hard to use is because I haven't learn yet about Inversion of Control Containers and the Dependency Injection pattern. Today I write my own mock objects without using any framework. However, if you want to use a Mock Framework, I strongly recommend Rhino.Mocks.

If you're not familiar with this pattern I recommend to read Jeremy Palermo's article Simple dependency injection to get you started with unit testing.

Sunday, April 8, 2007

Timer class

I was checking the difference in performance between SqlDataReader and DataTableReader. I needed something to measure time with. I wrote a simple class Timer. It worked just fine for me; however, I find it hard to believe that .Net framework doesn’t have anything to measure time. The reason for this post is that I hope that someone can suggest a better solution to my Timer class.
Here’s there Timer class:


public class Timer
{
  long _start;
  long _stop;

  public void Start()
  {
    _start = GetTimeInMilliseconds();
  }

  public void Stop()
  {
    _stop = GetTimeInMilliseconds();
  }

  public long TimeElapsed
  {
    get { return _stop - _start; }
  }

  private long GetTimeInMilliseconds()
  {
    return DateTime.Now.Hour * 60 * 60 * 1000
      + DateTime.Now.Minute * 60 * 1000
      + DateTime.Now.Second * 1000
      + DateTime.Now.Millisecond;
  }
}



In case you’re interested in performance difference between SqlDataReader and DataTableReader. Here’re my findings:
On single CPU machine SqlDataReader was faster and it of course was expected. However, on double CPU machine DataTableReader was slightly faster and this was a pleasant surprise for me.

Tuesday, April 3, 2007

Fixture order with MbUnit

In my company we have some people who are using NUnit and some are using MbUnit. I’m personally a huge fan of MbUnit. As a company we made a decision to use MbUnit only. Someone at my company had a problem with MbUnit because it would run tests in random order. In his case he wanted to run TestFixtures in specific order. He took advantage that NUnit runs TestFixtures in alphabetical order and named the fixtures in order he wants to run them. For example:

A_Fixture
B_Fixture

N_Fixture

To help to solve his problem I reflected on MbUnit.Framework.dll, and found DependOnAttribute. And that exactly what he wanted.

Here how it works. Let assume that we created four.

A_Fixture
Bad_Fixture
B_Fixture
B_Child_Fixture

[TestFixture]
public class A_Fixture
{
[
Test]
public void Success()
{ }
}

[TestFixture]
public class Bad_Fixture
{
[
Test]
public void Failure()
{
Assert.IsTrue(false);
}

[Test]
public void Success()
{
}
}

[TestFixture]
[
DependsOn(typeof(A_Fixture))]
[
DependsOn(typeof(Bad_Fixture))]
public class B_Fixture
{
[
Test]
public void Success()
{
}
}

[TestFixture]
[
DependsOn(typeof(B_Fixture))]
public class B_Child_Fixture
{
[
Test]
public void Success()
{
}
}

You can see that B_Child_Fixture depends on B_Fixture. B_Fixture at the same time depends on A_Fixture and Bad_Fixture. As you can see one of the tests in Bad_Fixture will fail. As a result B_Fixture and B_Child will not run.

Here's the result in the MbUnit GUI.


Sunday, April 1, 2007

AddressAccessDeniedException, Vista & Orcas

I just started playing with WCF. I created a simple service with VS 2005 on Vista and everything worked fine. Then I tried to use the same example on the same machine but use VS “Orcas” instead of VS 2005. Ooops. I got AddressAccessDeniedException. Thanks to Google I was able to find this article by Amit Lale where he explains the reason why the service doesn’t have rights to http://localhost:8000/ namespace and how to resolve this problem. Using his suggestion to use netsh utility, I was able to get rid of the exception. It also became very clear why it worked for VS 2005 and not VS “Orcas”. To be able to run VS 2005 on Vista I had to run VS 2005 as Administrator and when press Ctrl-F5 or F5 the service also ran as Administrator. However, you don’t need to run VS “Orcas” as an Administrator and the service of course runs as VS user that doesn’t have rights to listen to http port 8000.

I wonder how many security issues like this we’re going to have. Unfortunately security and convinience don’t go together and we have to learn how to live with this.