DCSIMG
October 2007 - Posts - Nati Dobkin

October 2007 - Posts

 

In the past few days I been dealing with setting up continues integration (CI) process in my team. The process is not finished yet but be ready for a post at the minute when it will be done.

CI is dealing with automated builds so I needed some automated build tool to handle the job. No so long ago I have been working with MSBuild, which is very powerful tool to manage your build process. However lately more and more often I run in to TFSBuild (which is a tool for automated build that come with TFS) relative with CI. I have seen tutorials about the tool and it seemed pretty simple. More over it has been written that this tool is based on MSBuild, and MSBuild we familiar with, so what can go wrong?! – In fact many things.

I have followed the guide lines and with a help of the tutorial I have made a new build type which included getting latest from the TFS source safe into my working directory, building the solution, running the unit tests and running the code analysis. So fare so well.

After a while I want to add some more tests to my build, which is a common task that every team member has to do at least once a week. Then I realized that there is no easy way to do that, the guide line said – "go to the safe source, check out of the build file, and then change the tests list hard coded" - why someone in my team have to care that there is some kind of build file!? But I said ok, let see where it goes. I have opened the build file and saw this task:

<IncludeDataFile Include="$(SolutionRoot)\MyProject\TestProject.vsmdi">
    <TestList>MyDalTest</TestList>
</IncludeDataFile>

When MyDalTest has to be a test list, which is a concept of VS 2005 for testers and not included in common VS 2005. Moreover I don’t want that for every test that someone of my teammate writes, he has to remember to add it to some kind of not understandable test list, and if some one will, one sunny day, forget to do this the test will never run at the CI process. I said "this is not the working process that I been looking for" and went to look for some alternatives. But before this I had to find out how Microsoft runs their test. So I go to the IDE folder in VS root installation folder, where I know Microsoft keep all their goodies, and I have found a command line tool that called MSTest.exe (you can find help about it here). I was surprised to see that this tool has very powerful ability to run tests in any form I only wish to, form running separate test to running .vsmdi files and entire solutions.

So as I see it Microsoft was able to make a very powerful tool to run their tests but someway hasn’t included it all features in their build process.

This disability of the team build running test and some other little thing that I had problem with made me to move to some better and more important more flexible alternatives like cruise control .net and standard MSBuild files

 

After my trip to Thailand Last month (see some photos) I back and jumped right in to coding. I wrote some code at work and tried to fix some unit tests for it using Rhino Mocks. I guess you all familiar with that powerful tool and I will not try to explain how to use it, it been done perfectly by some of my colleagues.

I wrote a class like this:

public class User 
{ 
  private void DoSomeLogic() 
  { } 

  public void Add() 
  { 
    DoSomeLogic(); 
    // ... 
  }
} 
When I came up to write the test I realized that the DoSomeLogic method, which I want to do some mocking and inject custom logic when I about to check the Add method, is not accessible from outside the class. So as good student I go and did what is written to do in such situation and make the DoSomeLogic method internal virtual and of course added:

[assembly: InternalsVisibleTo("MyAssembly.Test")]

To assemblyInfo file.

After that I managed to access this method and wrote test that looked like this one:

[TestMethod] 
public void Add_LogicFlow_Ok() 
{ 
  Rhino.Mocks.MockRepository mocker = new MockRepository(); 
  User user = mocker.CreateMock<User>(); 
  using (mocker.Record()) 
  { 
    user.DoSomeLogic(); 
  } 
} 

And my class, after the change, looked like this:

public class User 
{ 
  internal virtual void DoSomeLogic() 
  { } 

  public void AddUser() 
  { 
    DoSomeLogic(); 
    // ... 
  } 
} 

I run the test, with hope that it will pass. But, as you know, the life is no so simple and I got an exception that look very strange because it looked like it came from my original DoSomeLogic method - isn’t the user instance is a mock?!

Before I manage to say "WTF", which is very sort acronym, I was on debug mode to see what is going on. And in fact the user.DoSomeLogic(); - which is inside my record statement, went directly to my original User.DoSomeLogic() – what is definitely not what I meant to do.

I try digging and se what is wrong. After a while and with help of yoav we came up with conclusion that Rhino can not access this method (because it internal) and cannot override it when it mocking my class.

A solution to this problem can be made by two ways.

1. add protected to the definition of the method like this:

public class User 
{ 
  protected internal virtual void DoSomeLogic() 
  { } 

  public void AddUser() 
  { 
    DoSomeLogic(); 
    // ... 
  } 
} 

2. add [assembly: InternalsVisibleTo("Rhino.Mocks")]

The first solution is missing some basic purpose of what I have intended to do, because in such case you open an opportunity for deriving class to override logic (DoSomeLogic method ) which, as fare as you remember, was private at the beginning. This solution is useful only if the class itself is internal. In that case you anyway need to go to second solution, in order to Rhino could see the class and mock it. So this is what I did. I add the necessary line in to assemblyInfo and added to it the public key of the Rhino assembly (which I get by running command line - "sn –Tp Rhino.mocks.dll") something simple like this:

[assembly: InternalsVisibleTo("Rhino.Mocks, PublicKey=00240000048000009400000006020000002400005253413100040000010001009D1CF4B75B7218B141AC64C15450141B1E5F41F6A302AC717AB9761FA6AE2C3EE0C354C22D0A60AC59DE41FA285D572E7CF33C320AA7FF877E2B7DA1792FCC6AA4EB0B4D8294A2F74CB14D03FB9B091F751D6DC49E626D74601692C99EAB7718ED76A40C36D39AF842BE378B677E6E4EAE973F643D7065241AD86ECC156D81AB")]

Unfortunately it hasn't helped. I still was unable to make a mock of my user type. As you can figure the same problem will appear testing a internal classes.

After hitting some values at Google I figured that Rhino come with very helpful constant - Rhino.Mocks.RhinoMocks.StrongName which holds the assembly name and public key (which apparently is different from the one that I have found). So after I add this line

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

My user type could be mocked and the test finally passed!