I’m doing some work with TypeMock and I start to love it more and more. For example, how about removing your database completely from your continuous tests? Sure you can do some database testing during the nightly build, but please keep the tests as fast as possible.
A little story about a build Just a few days ago on a Friday my colleague Alex Thissen and I were planning to leave the building. Unfortunately after checking in some code, a few unit tests failed in Alex’s project. It were some really minor changes, but as it was 20:00 hours already, we weren’t as sharp anymore. After 4 trial-and-error sessions getting the test to work, we could go home. The code changes took only a few seconds, running the build took much, much longer. Mainly because Visual Studio 2008 for DB Professionals was deploying the database every time. What if we only needed that during the nightly build and actually had the continuous build running much faster?
Imagine a nice little table like the one on the right. Just some Class-A trainers in there. Imagine some code retrieving the trainers.
public List<MyTrainer> GetTrainers()
{
List<MyTrainer> trainers = new List<MyTrainer>();
using (SqlConnection con = new SqlConnection())
con.ConnectionString = @"Server=.\sqlexpress;database=courses;integrated security=sspi;";
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "select * from trainers";
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
MyTrainer t = new MyTrainer();
t.Name = rdr["Name"].ToString();
trainers.Add(t);
}
return trainers;
Normal ADO.NET code for retrieving trainers and adding them to a collection of MyTrainer objects. We could just test this with a special test database so that we always get the same results. We could create a very easy test where we just execute the GetTrainers method and see what data it returns. But as this accesses the database you might want to do this in a nightly batch. To be a little more sure you don’t break the build at night, you can always run these tests from your local machine.
[TestMethod]
public void GetTrainers_DBAccessed_Return7Trainers()
DAL dal = new DAL();
List<MyTrainer> trainers = dal.GetTrainers();
Assert.IsNotNull(trainers);
Assert.AreEqual(7, trainers.Count());
Assert.AreEqual("Anko Duizer", trainers[0].Name);
But we really want to test the code without actually connecting to the database. You could stub out a lot, but that’s a lot of work. Especially because the datareader is very hard to stub out. I’ve once used a datareader that was running on a dataset with one ore more tables in it. Pretty nice, but still took a whole lot of code to fill the datareader initially.
When we want to use a mocking framework like TypeMock, it still requires some code. We need to actually mock out three objects and create expectations for them. Here’s the code.
[TestMethod, VerifyMocks]
public void GetTrainers_NoDBAccess_Return2Trainers()
using (RecordExpectations rec = RecorderManager.StartRecording())
con.ConnectionString = "";
cmd.CommandText = "";
SqlDataReader fakeReader = RecorderManager.CreateMockedObject<SqlDataReader>();
rec.ExpectAndReturn(cmd.ExecuteReader(), fakeReader);
rec.ExpectAndReturn(fakeReader.Read(), true).Repeat(2);
rec.ExpectAndReturn(fakeReader["name"].ToString(), "Dennis van der Stelt");
rec.ExpectAndReturn(fakeReader["name"].ToString(), "Alex Thissen");
Assert.AreEqual("Dennis van der Stelt", trainers[0].Name);
Assert.AreEqual("Alex Thissen", trainers[1].Name);
As you can see we set up a recorder and created expectations for the values that should be returned. The reader.Read method should return true twice so we can fill two MyTrainer objects with data. We then set expectations for the two times the name column is accessed using the reader. When finished recording, we actually execute the code we’re testing and mocking. Of course this is a very simple implementation, but it’s to show how to mock things out. For more advanced scenarios you should check the TypeMock manual.
Now let’s see how we would retrieve the same data with LINQ.
public List<Trainer> GetTrainersViaLINQ()
CoursesDataContext db = new CoursesDataContext();
var query = from t in db.Trainers
select t;
return query.ToList();
This is a lot less code. When we want to mock this out, we again use a recorder and just use the same code. However LINQ to SQL returns an IQueryable collection of Trainer objects. You can’t use recorder.Return(someList.AsQueryable()) inside the recording-block because then the AsQueryable would be mocked out as well. So we have to prepare the collection of trainers in advance.
public void GetTrainersViaLINQ_NoDBAccess_Return2Trainers()
var fakeTrainers =
(new [] {
new Trainer() { Name = "Dennis van der Stelt" },
new Trainer() { Name = "Alex Thissen" } }
).AsQueryable();
rec.Return(fakeTrainers);
IEnumerable<Trainer> trainers = dal.GetTrainersViaLINQ();
Assert.AreEqual(2, trainers.Count());
Assert.AreEqual("Dennis van der Stelt", trainers.ElementAt(0).Name);
Assert.AreEqual("Alex Thissen", trainers.ElementAt(1).Name);
You can see I prepared the fakeTrainers collection in advance, start recording and set the return value to the prepared collection. I then actually execute the code inside my tested class and assert that everything’s as expected.
How about this, a pc in/on a napkin to use, read, write, collaborate with and more…
As you see in the picture on the left, there are enough in the holder and you can grab one to work with. Or each member of the team grabs one and start drawing out ideas and exchange napkins to share ideas and work them out more.
When you combine napkins you can create larger surfaces and present something to the team. The idea sounds awesome and I can only hope something like this will become reality. For now, it’s just an idea from a contest. Unfortunately.
Marco mailed me this morning with the following sentence
Unit tests are meant to test functionality, NOT code! That means if you write your unit tests after the fact, you’re probably not focusing on the functionality.
This comes from two weblogs that have some unit testing comments. Jason Young posted the sentence and he refers to Obishawn who also has something to say. Why I’m writing this post is for two reasons. Or three actually. The first reason is that I liked the quote. The second reason is that Obishawn tries to prove that you should even test properties, something not many people do. But his argument is that it can grow to something that you definitely would want to test, so you should have a test in place to test the functionality. He also states that you should not trust your framework and although he’s probably right, I wouldn’t test my properties because I don’t trust the framework. If that’d be the case, it’d probably be enough to test a single property because with that I’d have tested them all. I know the .NET Framework has its bugs, but I hope to find these when writing tests that target my own code functionality.
Anyway, Obishawn also provides a few lines of code to prove you should test properties. I have written a small piece of code to expands on this a bit. There are three errors in it and maybe you can spot them. Although these are extremely simple (once you know which ones I mean) it’s an example of why you should seriously consider writing tests for all your code functionality.
public class CoD4 : Game
private List<string> _redPlayers;
private List<string> _bluePlayers;
private string _name;
public CoD4()
this.Name = "Call of Duty 4";
public List<string> BluePlayerCount
get { return BluePlayers.Count(); }
public string Name
get { return Name; }
public void AddPlayer(string name)
base.AddPlayer(name);
if (_redPlayers.Count <= _bluePlayers.Count)
_bluePlayers.Add(name);
else
_redPlayers.Add(name);
A little snippet that I use from time to time when I need information on how long something takes. Type ‘sw’ (without the quotes) and tab-tab.
Installation is easy, just create a file called “sw.snippet” in your %Documents%\Visual Studio 2008\Code Snippets folder and paste the following in the file. You can use it immediately without restarting Visual Studio.
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Add Stopwatch code</Title>
<Shortcut>sw</Shortcut>
<Description>Code snippet for adding complete Stopwatch usage and display of elapsed time.</Description>
<Author>Dennis van der Stelt</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<References>
<Reference>
<Assembly>System.Diagnostics</Assembly>
</Reference>
</References>
<Code Language="csharp">
<![CDATA[Stopwatch sw = new Stopwatch();
sw.Start();
sw.Stop();
TimeSpan ts = sw.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine(String.Format("\n\nProcessing time : {0}", elapsedTime));]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
You might know that I’m quite the Microsoft addict. While a lot of people are very sceptic with everything Microsoft releases, I tend to have a positive feeling for everything Microsoft releases, at first. After some experience, I might hate or love it, or just don’t use it because I don’t feel the need for it. Microsoft Sync, Parallel extensions and many more products and frameworks; after I get my hands dirty with it I’ll decide if it does any good for me or not.
About Office Live Workspace, I know there are many alternatives to it but I really want to give this a change. Everything looks good (I almost always like Microsoft GUI's), looks familiar, has a nice Office plugin and some other benefits. And hey, it’s a Microsoft product! ;-)
I just read they released new languages and that May was a very hectic month for them. But I seriously can’t believe why they don’t introduce folders. Everyone is crying out for folders but instead of folders, we get more languages and other stuff. So I thought, let’s see when they’ll introduce folders and went to their blogs. Of course (?) you have to login to place a comment. So I click the little Passport (or Windows Live ID) login icon at the top-right corner. But I get presented a login/registration screen. First thing I thought was that this was some phising attempt for my Windows Live ID username and password. Why use the icon and have a different registration system. Heck, why a different registration system at all? So I left the blogs and decided to write a long and boring post on my own weblog. And guess what, anonymous comments are enabled! :)
Anyway, I’ve registered for a workspace months ago and would really like to use it, but haven’t done so yet. Simply because of the lack of folders. I’m not even going to upload a small amount of folders to later find out I have to move every single one of them via a web interface.
Please introduce folders into Office Live Workspace! Thanks.
Two tools I absolutely love!
Windows Live Writer A new version was just released, June 2nd. Download it here.
Sysinternals ZoomIt Version 2.0 was released on May 28. I just downloaded that version myself and it has some nice features. However, I did not know about all 1.x existing features myself. I just saw a part of the TechEd keynote and noticed this guy was drawing rectangles and arrows. I thought : “What tool is this guy using? Can it be my favorite tool ZoomIt?” And yes he was!!!
Now I did not know that! New features in 2.0 (afaik) are:
Sw33t!!!
This has taken us some time; depending on which environment you are, telling Visual Studio 2008 for Database Professionals Edition (or simply DataDude) what user it should use to deploy the SQL scripts, during an automated build. We're working with Windows XP users, Windows Vista users and Windows 2008 Server. As you might now, XP uses the "ASPNET" user to run IIS and Vista and 2008 use the "Network Service" user.
We're using FinalBuilder, a most excellent product, which in turn is using MSBuild and were trying to figure out how to pass variables to MSBuild, who should pass them to DataDude, which in turn would have to pass them to SQLCommand. Sounds difficult, but when you've figured it out, it's quite easy! :-)
The goal is to use "Network Service" when automated and let the user specify what user to use when running locally.
Here are the steps we took
<PropertyGroup Condition=" '$(Configuration)' == 'Default' ">
<SetVariables>
<Variable Name="TargetUser" Value="ASPNET" />
</SetVariables>
</PropertyGroup>
<Variable Name="TargetUser" Value="$(DatabaseUser)" />
<DatabaseUser>aspnet</DatabaseUser>
If you're interested how to use this in FinalBuilder, here's how.
Good luck! :-)