DCSIMG
Doron's .NET Space

Tip for Profiling NUnit Tests

This is just a tiny little note that can save you some precious time. This article explains exactly what you need to do in order to profile NUnit tests with dotTrace (gotta love products with special placement of capital letters) 4.0, except it misses an important detail. The latest versions of NUnit run the actual tests in a separate process, called nunit-agent.exe. So, if you profile nunit-console.exe you won’t see your code there at all. You have to run NUnit in a single process mode. To do that just add /process:Single to the nunit-console command line arguments, and everything should work nicely now.

Posted by dorony | with no comments
תגים:

How to Save a Unicode Text File That Excel Can Read

The other day I had to create a .CSV file with some funky Unicode characters. Not only that, but Excel had to be able to open and edit it. When using .NET’s StreamWriter default constructor, it uses a default encoding of UTF-8 without BOM (byte order mark), which Excel can’t read.

Well, actually, it can read it, but it doesn’t realize that this is a unicode file and special characters (such as this lovely one - Ž) have a tendency to look like someone just puked a letter on the screen.

The solution is quite simple. You need to use the other StreamWriter constructor, which accepts Encoding. You then have to pass it an Encoding of UTF-8 with BOM, which you can create by using the non-default constructor of the UTF8Encoding class. The whole thing looks something like this:

   1: private static readonly Encoding Utf8WithBom = new UTF8Encoding(true);
   2:  
   3: public void WriteSomething()
   4: {
   5:     using (var streamWriter = new StreamWriter(@"c:\hello.csv", true, Utf8WithBom))
   6:     {
   7:         streamWriter.WriteLine("hello,world");
   8:     }
   9: }

By the way, this is more of an issue with Excel then with .NET. As the above Wikipedia article states, the UTF-8 specification doesn’t require the BOM, and most applications can do without it.

Posted by dorony | with no comments
תגים:

A Trip to Java Land

I’m a C# guy, and always have been. I haven’t done any Java-ing since my days at the university, so I was glad of the opportunity to a do Java-related task at work. It was really a tiny little thing, but I got a little taste of the state Java is in and thought I would share.

Now, I’m hardly objective, and I’m basing this on a few hours of work tops. Also, any criticism I have is against Java the language, not Java the Framework.

So, with the disclaimers out of the way, let the rant begin. Basically, coding in Java is like coding in some sort of non existent C# 1.5. Here’s why:

No Linq and Lambda expressions. I found myself implementing stuff like Max and Average which I thought I would never have to again. I didn’t realize how used I got to the productivity that Linq+lambda expressions enable. They really have to write a lot of loops in Java, which is no fun.

Generics in Java suck. Basically, in Java a List<String> is a List<Object> and not a type by itself. This means, that among other issues, you can’t create a List<int>, only a List<Integer> so boxing is required, and performance suffers. This was done for backward compatibility purposes – since in Java generics is a compiler feature and not a framework supported feature, newer code can run on older versions of Java. But it results in a Generics implementation that is much worse than the C# one. This is the reason I think Java 7 is actually not as good as C# 2.0 was (not to talk about C# 4.0).

Simple operations are not simple enough. This is probably me at my most nitpicking, but I was really missing stuff like File.ReadAllLines and other file operations in Java. Of course, they can be easily implemented and I’m sure many did implement them, but it’s nice of .NET to give this out of the box. I consider this nitpicking, because there are probably lots of library methods in Java that are missing in C# and I just don’t know them. But still, reading a file, come on, make it trivial!

To end in a more positive note, as someone who hardly knows any Java I was up and running with an IDE (netbeans) in no time, and the experience was pretty similar to Visual Studio. It is definitely beginner friendly, and there is a ton of material on the web. Too bad the language is not up to par.

Posted by dorony | with no comments

Visual Studio x64 is Not to Be

I was informed today that a Visual Studio user voice issue I voted on was dismissed. The issue is “Create an x64 version of Visual Studio”, and around 1300 people voted for it. Sadly, Microsoft decided it’s not going to happen any time soon. Visual Studio’s program manager, Nathan Halstead, explains:

After reviewing telemetry on memory utilization, the scale of typical data sets loaded in Visual Studio, and hardware trends across our user base, we determined that one of the most effective ways to improve memory utilization across our entire user based would be to directly focus our efforts on overall memory reduction and improving scalability of key pieces of the product working with large data sets. While creating an x64 version of Visual Studio would unlock a virtually unlimited amount of memory to the Visual Studio process, most of our users would not see a direct performance or reliability benefit from this change alone.

In essence, building an x64 version of VS is a huge undertaking, and they just don’t think it’s worth it. Most users won’t tell the difference. Visual Studio 11 is already known to not have native x64 support, and looks like we can’t expect version 12 to be any different.

And that, well, kinda sucks. Why? Well:

I am regularly approaching the 2GB memory limit in my VS process. Visual Studio + Resharper work their magic together. As projects get bigger and more complex, it seems almost crazy to me that Microsoft doesn’t intend to support the ever growing demands of teams working with its IDE, and more than a few plugins. They may reduce the IDE memory consumption itself, but they can’t control the amount of memory plugins use – and plugins like Resharper are almost a must in every developer’s toolbox these days. And you can be sure that as the tools we use get smarter, they would need more memory. So yes, it’s a big project, but if they don’t begin it now, they’ll have some angry developers on their heads in a couple of years.

Posted by dorony | 1 comment(s)
תגים:

Sets of Mutable Objects is a Bad Idea

I guess this is something that is obvious to many, but it really had me stumped yesterday. I was looking at code that was joining two HashSets, that both had the same item. Not the same reference, but they had the same hash code, and Equals between the items returned true. And yet, Set1.UnionWith(Set2) changed Set1 to have two items. That seemed insane. Isn’t it in the contract of HashSet to not contain the same item twice? How could it be? It took a while, but I figured out the issue. Let’s try to recreate a situation where a set contains two identical items.

First, let’s define a Person class.

   1: public class Person : IEquatable<Person>
   2: {
   3:     public Person(string firstName, string lastName)
   4:     {
   5:         FirstName = firstName;
   6:         LastName = lastName;
   7:     }
   8:  
   9:     public string FirstName { get; set; }
  10:     public string LastName { get; set; }
  11:  
  12:     public bool Equals(Person other)
  13:     {
  14:         if (ReferenceEquals(null, other)) return false;
  15:         if (ReferenceEquals(this, other)) return true;
  16:         return Equals(other.FirstName, FirstName) && Equals(other.LastName, LastName);
  17:     }
  18:  
  19:     public override bool Equals(object obj)
  20:     {
  21:         if (ReferenceEquals(null, obj)) return false;
  22:         if (ReferenceEquals(this, obj)) return true;
  23:         if (obj.GetType() != typeof (Person)) return false;
  24:         return Equals((Person) obj);
  25:     }
  26:  
  27:     public override int GetHashCode()
  28:     {
  29:         unchecked
  30:         {
  31:             return ((FirstName != null ? FirstName.GetHashCode() : 0)*397) ^ (LastName != null ? LastName.GetHashCode() : 0);
  32:         }
  33:     }
  34: }

Note how the hash code computation takes both properties into account (this is Resharper’s auto generated code).

And now, let’s pass a test:

   1: [Test]
   2: public void MakeASetWithDuplicateValues()
   3: {
   4:     //The objects start out different
   5:     var p1 = new Person("Doron", "Yaacoby");
   6:     var p2 = new Person("Doron", "Y");
   7:  
   8:     //we put them in sets
   9:     var set1 = new HashSet<Person> { p1};            
  10:     var set2 = new HashSet<Person> { p2 };
  11:  
  12:     //we now make them equal
  13:     p2.LastName = "Yaacoby";
  14:     Assert.That(p1, Is.EqualTo(p2));
  15:     
  16:     //union create a set with duplicate values
  17:     set2.UnionWith(set1);
  18:     Assert.That(set2.Count, Is.EqualTo(2));
  19: }

So what happens here? We change set2’s item, but the set doesn’t know about it. It already computed p2’s hash code and stored it accordingly. It doesn’t know that its hash code has changed later. So when it comes to add p1 to the set, it thinks p1 is a brand new item with a brand new hash code, and lets it in.

Conclusion: do not change objects that are in sets, or even better – don’t create sets of mutable objects.

Posted by dorony | 1 comment(s)
תגים:

Inheritance is Truly Evil

Lately I’ve been refactoring some really old code, and it helped me realize that in about 90% of the cases, inheritance from a class (unlike interface implementation) is a Bad Thing. Of course, I’m hardly the first to think that, but it’s not until I had to refactor deep, and absolutely wrong, object graphs until I felt it in my bones.

But why? Isn’t inheritance a legitimate way to reuse code?

Well, no, for several reasons:

  1. It makes the code harder to understand. To understand the flow of your class, you have to go all the way up to the highest base class, and follow the protected method route, which are implemented in various child classes. It’s a torture.
  2. It makes the code harder to test. Are your tests really testing the class itself, or its base class. If you want to test the class itself, and not base class, how do you mock it out?
  3. It makes the code harder to maintain. Adding new functionality can be complicated, as you decide to add it to the base class, or its child classes.

In fact, I suggest that whenever you’re writing a “BaseThingy” class, you should rethink your design, and prefer interface implementation and composition instead. Composition solves all three issues, and in most cases, is a much better choice. In fact, "Composition over Inheritance” is such a well accepted notion, that it even has its own Wikipedia article.

Posted by dorony | with no comments
תגים:

Why doesn't ConcurrentBag implement ICollection<T>?

Hopefully you’ve encountered by now the System.Collections.Concurrent namespace. It’s new to .NET 4, and it has many useful data structures which are optimized for multi-threaded usage. ConcurrentBag, for instance, is an unordered collection of objects, which multiple threads can add and remove objects from at the same time.

Recently I needed to test that some piece of code was thread-safe. To do that, I wanted to run it once synchronously, and once asynchronously. It looked something like that:

   1: private static IEnumerable<ComputationResult> ComputeSynchronous(IEnumerable<string> inputs)
   2: {
   3:     Console.WriteLine("Starting synchrnous correction.");            
   4:     var results = new ConcurrentBag<ComputationResult>();
   5:     foreach (var input in inputs)
   6:     {       
   7:         //Some more printouts and work here
   8:         var result = computation.Compute(input);                
   9:         //Some more printouts and work here
  10:         results.Add(result);                
  11:     }
  12:     return results;
  13: }
  14:  
  15: private static IEnumerable<ComputationResult> ComputeAsynchronous(IEnumerable<string> inputs)
  16: {
  17:     Console.WriteLine("Starting asynchrnous correction.");
  18:     var results = new ConcurrentBag<ComputationResult>();
  19:     Parallel.ForEach(inputs, input =>
  20:         {                    
  21:             //Some more printouts and work here
  22:             var result = computation.Compute(input);
  23:             //Some more printouts and work here
  24:             results.Add(result);                    
  25:         });
  26:     return results.ToList();
  27: }

And so, the first method computes stuff in one thread, and the second does the same computation on the same inputs, but inside a parallel loop. This is all nice and simple, but I was a little bothered by the fact the the code inside the loop in the two methods repeats itself. The logical conclusion would be to extract a method, of course. This should look something like this:

   1: private static void ComputeAndAdd(string input, ICollection<ComputationResult> results)
   2: {
   3:     //Some more printouts and work here
   4:     var result = computation.Compute(input);
   5:     //Some more printouts and work here
   6:     results.Add(result);                        
   7: }

Only, you can’t write this method. If you try to pass it a ConcurrentBag<T> it will not compile, since that class doesn’t implement ICollection<T> nor IList<T>. This seemed strange. You can add and remove items from this collection. You can iterate it, why doesn’t it implement a more robust interface (you only get IEnumerable<T> and the non-generic ICollection, which doesn’t have an Add method). Baffled, I went and did the logical thing: asked in StackOverflow.

At first there was a suggestion to use SynchronizedCollection<T>, which does implement the interface I needed. But this is and older class that exists since .NET 2.0, and it isn’t as optimized as the newer ConcurrentBag. Also, it doesn’t really answer the question.

Later, user Rick Sladkey provided a better answer, and I’ll let him do the talking here:

A List<T> is not concurrent and so it can implement ICollection<T> which gives you the pair of methods Contains and Add. If Contains returns false you can safely call Add knowing it will succeed.

A ConcurrentBag<T> is concurrent and so it cannot implement ICollection<T> because the answer Contains returns might be invalid by the time you call Add. Instead it implements IProducerConsumerCollection<T> which provides the single method TryAdd that does the work of both Contains and Add.

So even though it seems That ConcurrentBag<T> implements the contract of ICollection<T>, it really doesn’t. There’s an underlying contract, that isn’t expressed in the interface’s methods, which ConcurrentBag<T> simply can’t implement. Rick then goes on and suggests using delegates to solve the above problem, a decent solution.

Posted by dorony | with no comments

Serializing a string as CData in WCF

We’ve hit an annoying issue a while ago. We are publishing a WCF web service which is consumed by several clients, and one of them failed to see leading and trailing spaces when reading the message. In order to solve this, without having to change and redistribute the client, we wanted to return some of the strings wrapped by a CData element. WCF doesn’t have a builtin mechanism for this, but we’ve found a suggestion to use the CDataWrapper class to acheive this.

This works, but it also changes the schema. In fact, .NET clients will see the CDataWrapper class as a DataSet in the generated proxy. In order to make a CDataWrapper property appear as a string in the WSDL, we use the XmlSchemaProvider attribute. Here is the entire CDataWrapper class we used:

   1: [XmlSchemaProvider("GetSchema")]
   2: public sealed class CDataWrapper : IXmlSerializable
   3: {
   4:  
   5:     public static XmlQualifiedName GetSchema(XmlSchemaSet xs)
   6:     {           
   7:         return XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String).QualifiedName;
   8:     }
   9:  
  10:     // implicit to/from string
  11:     public static implicit operator string(CDataWrapper value)
  12:     {
  13:         return value == null ? null : value.Value;
  14:     }
  15:  
  16:     public static implicit operator CDataWrapper(string value)
  17:     {
  18:         return value == null
  19:                    ? null
  20:                    : new CDataWrapper
  21:                          {
  22:                              Value =
  23:                                  value
  24:                          };
  25:     }
  26:  
  27:     public System.Xml.Schema.XmlSchema GetSchema()
  28:     {            
  29:         return null;
  30:     }
  31:  
  32:     // "" => <Node/>
  33:     // "Foo" => <Node><![CDATA[Foo]]></Node>
  34:     public void WriteXml(XmlWriter writer)
  35:     {
  36:         if (!string.IsNullOrEmpty(Value))
  37:         {
  38:             writer.WriteCData(Value);
  39:         }
  40:     }
  41:  
  42:     // <Node/> => ""
  43:     // <Node></Node> => ""
  44:     // <Node>Foo</Node> => "Foo"
  45:     // <Node><![CDATA[Foo]]></Node> => "Foo"
  46:     public void ReadXml(XmlReader reader)
  47:     {
  48:         if (reader.IsEmptyElement)
  49:         {
  50:             Value = "";
  51:         }
  52:         else
  53:         {
  54:             reader.Read();
  55:             switch (reader.NodeType)
  56:             {
  57:                 case XmlNodeType.EndElement:
  58:                     Value = ""; // empty after all...
  59:                     break;
  60:                 case XmlNodeType.Text:
  61:                 case XmlNodeType.CDATA:
  62:                     Value = reader.ReadContentAsString();
  63:                     break;
  64:                 default:
  65:                     throw new InvalidOperationException("Expected text or CData but was: "+ reader.NodeType);
  66:  
  67:             }
  68:         }
  69:     }
  70:  
  71:     // underlying value
  72:     public string Value { get; set; }
  73:  
  74:     public override string ToString()
  75:     {
  76:         return Value;
  77:     }
  78: }

In order to use this in an object you want to send over the wire, you will write something like this (again, taken entirely from here):

   1: // example usage
   2: [DataContract(Namespace="http://myobjects/")]
   3: public sealed class MyType
   4: {
   5:     public string SomeValue { get; set; }
   6:     [DataMember(Name = "SomeValue", EmitDefaultValue = false)]
   7:     private CDataWrapper SomeValueCData
   8:     { 
   9:       get { return SomeValue; }
  10:       set { SomeValue = value; }
  11:      }
  12: }

And that’s all there is to it.

Posted by dorony | with no comments

Bye Bye, Web ADF

Dave Bouwman noticed that ESRI has annouced that the Web ADF will be deprecated after ArcGIS 10. To me that’s not very surprising. I’ve blogged about my dislike to this framework more than once, and to me its death cannot come any sooner. I guess ESRI noticed that the simplicity of the REST API’s is winning the customers, and decided to back off the wretched thing. So is this good news? Ultimately, yes. The less people trying to make software with the ADF, the better.

But it is a mistake that ESRI should have noticed sooner. To think about the amount of changes the ArcGIS Server APIs went through since version 9.1 makes my head hurts. Upgraded from 9.1 to 9.2? Poof! The framework completely changed and WebADF with all new controls was born. 9.2 to 9.3? Poof! The Ajax framework got replaced and most of your Javascript code can go to the recycle bin. Wanted to change to the new and much better Javascript API? Better get on the dojo train and rewrite everything yet again.

If you were to try to take advantage of the greatest new features of each release, you probably had to rewrite your application every time. ESRI’s idea of backward compatability tends to be “let’s hope our customers won’t notice that we changed everything yet again”.

Posted by dorony | 2 comment(s)
תגים:

Easy Testing Of NHibernate.Spatial Code

In my current project we’re using NHibernate.Spatial against an SQL Server 2008 DB. This replaces our need to work with the cumbersome ArcSDE when writing and reading data in our applications (while still allowing ArcMap users to view the maps it holds by registering the tables in SDE). This made our life so much lovelier. We now have real domain objects to work with, and absolutely no COM is required to do stuff!

Anyway, we’re using the awesome Fluent NHibernate to map all our entities, and in order to test them, we have a base class (something like this) that all our tests use. The problem is, we want our tests to run against the in-memory SQLite database, but it doesn’t support the spatial stuff, and there is no NHibernate.Spatial dialect for it. A problem indeed – most of our code has nothing to do with geography, and it would be a damn shame if we couldn’t use an in-memory database to test it easily.

Well, we ended up using a cool feature of Fluent NHibernate, that allows us to specify conventions for our class maps. For instance, lets say we have a Country entity, which looks like this:

   1: public class Country
   2: {
   3:     public virtual int Id {get; set;}
   4:     public virtual string Name {get; set;}
   5:     public virtual IGeometry Location {get; set;}
   6: }

And the mapping for this class looks like this:

   1: public class CountryMap : ClassMap<Country>
   2:    {
   3:        public CountryMap()
   4:        {
   5:            Id(c => c.Id);
   6:            Map(c => c.Name);
   7:            Map(c => c.Location).CustomType(typeof(GeometryType));
   8:        }
   9:    }

This mapping class is problematic with SQLite, as this database doesn’t support using the custom GeometryType (which implements NHibernate’s IUserType) that comes with NHibernate.Spatial. If only we could do without specifying the custom type in our mapping, and use a different one in our tests files… Oh! Fluent NHibernate conventions let us do just that. We can use two different conventions, one for SQL 2008, which we will use in our production code, and one for SQLite, which will be used in most tests. Here’s how our convention for SQLite looks like (the one for SQL 2008 is exactly the same, only uses the above GeometryType custom type):

   1: public class SQLiteGeometryTypeConvention: IPropertyConvention
   2:    {
   3:        public void Apply(IPropertyInstance instance)
   4:        {
   5:            if (instance.Property.PropertyType.Equals(typeof(IGeometry)))
   6:            {
   7:                instance.CustomType(typeof (SQLiteGeometryType));
   8:            }
   9:        }
  10:    }

You can see that we’re using SQLiteGeometryType. If you don’t know what that is, it’s OK. It’s our own simple implementation, as defined below:

   1: public class SQLiteGeometryType: GeometryTypeBase<string>
   2:     {
   3:         public SQLiteGeometryType() : base(NHibernateUtil.String)
   4:         {
   5:         }
   6:  
   7:         protected override string FromGeometry(object value)
   8:         {
   9:             return value != null ? ((IGeometry) value).AsText() : null;
  10:         }
  11:  
  12:         protected override IGeometry ToGeometry(object value)
  13:         {
  14:             return value != null ? new WKTReader().Read((string) value) : null;
  15:         }
  16:     }

All we do here is tell NHibernate that when it sees an IGeometry property that it should persist, it should convert it to a string and save it as varchar. It also goes the other way around. GeometryTypeBase is a helper base class that exists in NHibernate.Spatial.

Now all that is left for us is to configure NHibernate to use our convention:

   1: Fluently.Configure()
   2:                .Database(SQLiteConfiguration.Standard.InMemory)
   3:                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Country>()
   4:                                   .Conventions.Add(new SQLiteGeometryTypeConvention()));

And now we’re done. We can persist our spatially-enabled entities to SQLite and write tests for them. Granted, we can’t use more advanced features like spatial queries that run in the database, but most of our code doesn’t do that anyway. Having an in-memory database is perfect for testing the OR mappings and domain service operations.

The ideal workplace

In less than three months I will be leaving my current position, and I started thinking about the kind of place I want to work at. Here are the points I thought of, with the most important ones appearing first:

  1. Awesome developers to work with. In my current workplace I’ve been one of the most veteran developers for a while, and it naturally put me in a teaching position. While I like teaching, I feel that the best way to learn is from others, and lately I’ve been learning less. In my ideal workplace I would be the junior developer, where people point at my code and say “yeah, but you could have made it a lot simpler by…”. So, smart, talented developers to learn from is definitely the most important thing to me in the new place.
  2. An interesting product. I want to work on something I believe in. I prefer working for a start-up company doing something very cool, over a safer enterprise environment doing in-house development. Also, I’m young and don’t mind working hard if I’m having fun and there’s a chance to hit the jackpot :)
  3. An agile environment. I was one of the people who implemented agile methodologies at my current place, and I would really want it to already exist in the new place. It’s not an absolute must for me, I guess, but if I have to convince everyone, yet again, that unit-tests are very very important, I might get very tired indeed.
  4. A comfortable working environment: a strong computer with a two monitor setup, a good chair (not a must, I guess, I can bring my own as I did in the last place), quiet offices with no more than 2 or 3 developers in each. The best software tools should be available, or at least a management that agrees to buy the stuff the developers need. I shouldn’t have to beg for a ReSharper license, right?
  5. Great atmosphere. Because work should be fun, not a chore.

I know it might not be realistic to find a job at such a place, but I would be very excited if I could.

If you live in Israel, and happen to work in my ideal workplace (or even your ideal workplace), and you’re looking for someone who loves developing great software, you can contact me and I’ll send you my C.V.

Posted by dorony | 1 comment(s)

A Spoon That Tests Your Web Site

This is just a quick recommendation: I recently discovered Spoon’s browser sandbox, which allows you to test a site against any browser. This way, you don’t have to keep your own virtual machine with XP just to test your web-app with IE6. I also found it useful when browsing older web sites that don’t support my choice of browser. Spoon does require you to install a plug-in in your PC, but after that it worked flawlessly for me.

Posted by dorony | with no comments
תגים:

PowerShell script to convert VSTS tests to NUnit

A while ago we decided to convert all our test projects to NUnit. We found Microsoft’s test framework to be overly complicated, much slower, and with less features.

So, in order to make the transition easier, I wrote this PowerShell script to convert VSTS test projects and files to NUnit. I didn’t know any PowerShell beforehand, so it took me a bit to get it right, but the script works nicely now. We’ve run it against dozens of test projects (VS 2005, VS 2008, and it also works with VS 2010 beta 2, as I tried it at home) in our company and it did the job. It should be noted that the script only works against NUnit 2.5 and above, and while it has worked well for us, you’re using it at your own risk. If you have source control, and of course you do, then you’re not risking anything anyway :)

You can download the script right here.

In order to use it you’ll need to:

  1. Download and install PowerShell. You already have it if you’re running Windows 7.
  2. Run PowerShell, and run Set-ExecutionPolicy “unrestricted”, so you’ll be able to run scripts. Under Vista\7 you’ll have to run PowerShell as administrator to get this done.
  3. Copy the script to a solution or a VSTS test project folder (I do recommend doing the conversion one project at the time, but the script just scans for .cs and .csproj files, so you can run it against any number of projects). This step is optional, you can also provide the working directory as a parameter to the script.
  4. Check-out all the project’s files from source control, if you need to.
  5. In PowerShell, run “.\VstsToNUnit.ps1 [NUnit Version] [Path from .csproj file to NUnit.framework.dll] [Working directory (optional if the script is copied to the project folder)]
    Example: .\VstsToNunit.ps1 2.5.3.0 ..\lib\nunit.framework.dll c:\myprojects\MyVisualStudioProject

What does this script do? Well, its essentially a bunch of regex replacements running against every .cs and .csproj file in the working directory. It replaces the VSTS attributes with NUnit ones, changes VSTS test projects to standard class libraries, and adds a reference to NUnit instead of the VSTS one. It will also:

  1. Save you from a few gotchas, such as the arguments order in Assert.IsInstanceOfType being different between the two frameworks.
  2. Remove some TestContext stuff Visual Studio generates automatically when you use the unit-tests generation feature. Note, however, that if you actually used the TestContext object you’ll have to refactor your unit tests.
  3. For users of Rhino.Mocks.Constraints, adds stuff like “using Is=Rhino.Mocks.Constraint.Is”, as NUnit also defines Is\List\Text classes, and it causes ambiguity when wanting to use the Rhino Mocks constraints.

Stuff the script won’t do:

  1. As I said, remove all the TestContext references. You’ll need to get some of those manually.
  2. Remove the [DeploymentItem] attribute. You’ll need to manually delete those, while making sure your test files are copied to the output directory for NUnit to find (right-click the file in your solution, and in the properties select “Copy to output directory – always”.
  3. Delete .vsmdi and .testrunconfig files. You’ll have to get them yourself. Wouldn’t want to steal that joy from you :)
  4. Perhaps a bunch of other VSTS specific stuff our projects don’t use.

If you’re using this, please let me know if you ran into any issue, or anything that should be added to the script, and I will update it here.

Posted by dorony | 1 comment(s)

Visual Studio 2010 Beta 2: My 5 Minutes Impressions

So I just installed VS 2010 beta 2, played with it for 5 whole minutes, and I have to say it looks pretty damn good.

  • Performance was horrid on Beta 1, but now it seems to be much improved.
  • Startup time is still too long if you ask me.
  • Opening the Fonts and Colors dialog is still the slowest thing in the world.
  • But the Add Reference dialog opens really fast! Finally they realized it is better to default on the project reference tab there.
  • The new WPF UI is beautiful. I like the “Code Optimized” web settings that remove all the non-critical toolbars and panels and leave lots of room for the code.
  • The new IntelliTrace (or historical debugging) feature looks very interesting.
  • F# Interactive seems to always be open, even on a C# project. Could be a useful tool, so I should probably get serious about learning F#.

I would also like to point out this excellent article, which talks about the VS2010 architecture. It’s great to see how Microsoft “dogfoods” its own products and in the process makes them better for the rest of us. It stands to reason that if WPF can work for a project like Visual Studio, and TFS can handle the entire Microsoft organization, these could be good choices for us simpletons.

Posted by dorony | with no comments
תגים:

Running VSTS tests without mstest.exe

I’ve been looking at ways to run VSTS tests without using the actual Visual Studio testing framework. It all started when I wanted to integrate code-coverage in our TeamCity daily build. All the solutions I found were using the NUnit runner for this, and while I could have used mstest.exe to run the tests when I’m gathering code-coverage, I didn’t want to. Why? Well, because:

  1. TeamCity doesn’t use it to run the tests, so I might get different result from the regular test-run and the code-coverage test-run.
  2. It requires me to install Visual Studio on the server.
  3. It creates annoying TestResult folders.
  4. It requires maintaining a testrun.config file.

In essence, using mstest.exe just seems a lot more cumbersome. Still, all our tests are indeed using the VSTS attributes, so I need a way to run them “NUnit-style”, i.e. without mstest.exe. TestDriven.Net and TeamCity already seem to be doing this, but without exposing anything that I could use. Google did not help, neither. So, I turned to ask at Stackoverflow.com. After a while, an answer was received by a fellow named Bryan Cook: an addin to NUnit exist, but alas, it turns out it doesn’t support the latest NUnit version. Kindly enough, Bryan just went and fixed it. Not a trivial task, mind you, as I had a look at the code, and it seems that the NUnit API went through quite a lot of changes going into version 2.5.

Anyway, you can go over and download the addin from right here. Thanks Bryan!

On a different note, we ended up deciding to switch all our tests to NUnit at the end, but I’m sure this could come handy in the future :)

Posted by dorony | 3 comment(s)
תגים:
More Posts Next page »