views:

307

answers:

2

We've just separated our SQL Server database adapters to allow for differences between SQL Server 2000 and 2005, specifically, the nvarchar(max) data type.

Because the code change is so small, instead of reimplementing our adapter interfaces and abstract base class, I subclassed the SQL 2005 adapter from SQL 2000 and just override the appropriate methods and properties.

public abstract class SqlDatabaseAdapter : DatabaseAdapter, ISqlDatabaseAdapter
...
public class Sql2000DatabaseAdapter : SqlDatabaseAdapter
...
public class Sql2005DatabaseAdapter : Sql2000DatabaseAdapter
...

Our unit test code previously just cast to a particular type of adapter and then made an assertion against that type, but now that we have an adapter factory method to build the appropriate SQL Server adapter (from configuration or found via SQL connection), I want to verify that the exact type is instantiated (since we now default to SQL Server 2005), the only problem is our old tests are passing when they should be failing :)

In the example below, the entity factory creates a Sql2005DatabaseAdapter, but the test passes because this type inherits from Sql2000DatabaseAdapter. And it also works further up the ancestor chain.

Entity foo = EntityFactory.Create("foo"); 
Assert.IsInstanceOfType(typeof(SqlDatabaseAdapter), foo.Adapter); // Should fail for test
Assert.IsInstanceOfType(typeof(Sql2000DatabaseAdapter), foo.Adapter); // Should fail for test
Assert.IsInstanceOfType(typeof(Sql2005DatabaseAdapter), foo.Adapter); // Should pass

I understand why it's passing, and I can use the general Assert.AreEqual method to fix this particular case.

Assert.AreEqual(typeof(Sql2005DatabaseAdapter), foo.Adapter.GetType());

But I'm curious if there's a way using Assert.IsInstanceOfType?

+1  A: 

I suspect that you you already know the answer here, you just don't like it :)

By saying Sql2005DatabaseAdapter : Sql2000DatabaseAdapter, you are saying that any instance of Sql2005DatabaseAdapter absolutely IS a Sql2000DatabaseAdapter. So then asking that Assert.IsInstanceOfType somehow pretends that it isn't... surely isn't going to work.

You have correctly given a way to test for the exact type - why don't you want to use this?

edit I meant to also say something similar to what David Schmitt has - this inheritance hierarchy feels wrong. It's not really true to say (talking about the real-world concepts) that a Sql2005DatabaseAdapter IS a Sql2000DatabaseAdapter, is it?

AakashM
So I don't fall for this problem again :) Seriously, it was only because we didn't have a factory method and was casting against a specific type that I found the problem with our tests (because I was refactoring out the specific type cast).
Si
+2  A: 

Since your Sql2005DatabaseAdapter presumably cannot work with a SQL 2000 server, the inheritance relationship is just wrong, since it effectively says "Sql2005DatabaseAdapter is a Sql2000DatabaseAdapter", thus leading to all kinds of weirdness, like the problem you are currently encountering in your test.

If you want to avoid this, it would be good to move most of the functionality into an abstract base class and have both inherit directly from that:

public abstract class SqlDatabaseAdapter : DatabaseAdapter, ISqlDatabaseAdapter
...
public class Sql2000DatabaseAdapter : SqlDatabaseAdapter
...
public class Sql2005DatabaseAdapter : SqlDatabaseAdapter
...
David Schmitt
Of course! Thanks David, guess I was too quick to start coding and didn't spend enough time thinking about the relationships.
Si