A number of readers of this blog have let me know that they have adopted the UnitTestBase and DatabaseUnitTestBase classes that I originally demonstrated from the Summer of NHibernate screencast series as a simple means of facilitating their writing of unit tests. This is great news as I’m glad others have been finding value in the library and I had of course encouraged anyone interested to try it out and adopt it if it met their needs.
These abstract base classes (from which consumers would derive their concrete test fixture classes) provide several convenience facilities that make it slightly easier for a developer to write tests that leverage the RhinoMocks mock objects framework as well as significantly easier to write tests that leverage the NDbUnit database-state-management framework when writing database-interaction unit tests (ok, technically these are integration tests, but you get the point).
Some of these conveniences are…
- built-in access to the RhinoMocks MockFactory without needing to instantiate one (the base class contains a member field that contains a pre-constructed MockFactory instance)
- simple convention-over-configuration defaults that allow a simple set of conventions for data files, schema files, and other elements to quickly setup, teardown, and reset your database contents to support your database integration testing
- convenience methods for interacting with the database and data to perform common repetitive tasks with ease
- Unit test type enums for annotating your tests in a 100% consistent manner so that build scripts, etc. can properly filter different kinds of tests to run them in different build configurations (e.g., on an automated CI server, etc.)
The Challenge
One of the challenges with #1 above is that this means that the UnitTest Utility Library has a dependency on the RhinoMocks framework. Its not a huge dependency since there is little integration between the two, but when it comes to a compile-time dependency, there is no such thing as a ‘small’ dependency. This means that when an updated version of RhinoMocks is released, an updated version of the UnitTest Utility needs to be compiled against the new RhinoMocks release. Such was the case when the RhinoMocks 3.5 RC1 build was released and it is again the case now that the final RTM build of RhinoMocks 3.5 has been released (as was the case earlier this week).
To satisfy the needs of those that have chosen to adopt the UnitTest Utility, I have now rebuilt the library against the RhinoMocks 3.5 RTM release and am making it available for download to anyone who is interested. (BTW, Sudarshan, this invitation doesn’t extend to you for reasons clear to anyone who ready this post from last week).
There are actually now two RhinoMocks releases called v3.5, one that targets the .NET 2.0 framework and another that targets the .NET 3.5 framework. This unfortunate situation (although I completely agree with Ayende’s reasoning for why he did this) has lead to the co-release of "RhinoMocks 3.5 for .NET 2.0" and "RhinoMocks 3.5 for .NET 3.5". I guess you know you’ve made it big-time when your own product versions are every bit as confusing as Microsoft’s ("C# 3.0 for .NET 3.0", "C# 3.0 for .NET 3.5 on the 2.0 CLR", etc.)
In any case, I am also releasing two builds of the same UnitTest Utility, one for .NET 2.0 (integrated with RhinoMocks 3.5 for .NET 2.0) and the other for .NET 3.5 (integrated with RhinoMocks 3.5 for .NET 3.5) that can be reached from the following download links…
- UnitTestUtility for .NET 2.0 (RhinoMocks 3.5 for .NET 2.0)
- UnitTestUtility for .NET 3.5 (RhinoMocks 3.5 for .NET 3.5)
A few Goodies snuck in
In addition to simply rebuilding the utility for the new RhinoMocks release, I’ve also taken the opportunity to introduce two new additional convenience methods to the UnitTestBase class:
GetInstanceFieldValue(…)
SetInstanceFieldValue(…)
Just as their names suggest (another point in favor of ‘intention-revealing-interfaces’ ), these two complimentary methods allow your test fixture class to use the .NET reflection API to get and set both public and private fields in any class. While reflection is generally frowned-upon in production code as being a performance drag, using it in unit tests to either get or set values on classes under test can be extremely useful to avoid the need to create public properties on objects just to ‘inspect’ their values at test-time, or perhaps to set a private field in the same way something like NHibernate might — by bypassing any public setter logic, etc.
To be clear, good unit test techniques suggest (and I generally agree) that if you are testing the internal, non-public aspects of your classes then you tend to be writing brittle unit tests that test the wrong things, but I believe in giving developers the tools they need and then trusting that they will do the right thing with them. And so I’m adding these two methods to the base class to support easily testing to ensure that simple things like constructor-injected dependencies end up in the right place inside a class’ private field(s).
Since the methods are internal and virtual, if you don’t like them at all then simply either ignore them or override them in your derived concrete class and fill their method bodies with code that does nothing. Your choice.
Also, as mentioned in this post when I released the updated build for RhinoMocks 3.5 RC1, both of these downloads also contain a CHM help file that documents (pretty clearly, if I say so myself ) the entire reasonably simple API for this library of base classes so anyone interested is encouraged to download either of the packages from the preceding links to review the compiled HTML help file contents.
As always, any comments, feedback, etc. is much-appreciated. Have fun and happy coding~!
I’m also using your little utility, but unlike Sudarshan, in it’s original form ๐
Just wanted to thank you on the effort you put in Summer of NHibernate series. Can’t wait for Autumn of Agile ๐
Hm, I just upgraded my test project to use new versions of Microdesk.Utility.UnitTest and Rhino.Mocks, and the tests are failing with this exception:
System.IO.FileLoadException: Could not load file or assembly ‘Rhino.Mocks, Version=3.5.0.2, Culture=neutral, PublicKeyToken=0b3305902db7183f’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Same exception using 3.5 and 2.0 versions. I’ve also tried to create a new test project referencing those assemblies. Same exception again. Is it possible that you have added the wrong version of Rhino.Mocks to zip files?
@Miroslav:
That sure sounds like what happened. I just updated the ZIP files again (same filenames, same links) so try again and advise results. The ‘confusion’ is made worse by the fact that the RhinoMocks DLL that was the RC1 release was stamped v3.5.0.2 but that both of the RTM versions are tagged with v3.5.0.1337 which would lead one to believe that they are OLDER than the RTM build (which obviously cannot be the case).
Any any event, try again and let me know if this resolves it for you; sorry for any confusion from this — at least they are small downloads ๐
This time it’s working as advertised ๐
Both versions are tested. Thanks for a quick update.
@Miroslav:
Thanks for the feedback, sorry about the mixup. It turns out that I think the correct version of the RhinoMocks dll was included in the prior ‘broken’ packages I posted, but since I failed to hit CLEAN SOLUTION between builds, the change to just a dependent DLL in your solution doesn’t result in a recompile when issuing a BUILD action. I’m not sure whether I should consider this a ‘bug’ in VS or a ‘feature’, but its certainly somewhat unexpected since I (personally) think the build action should trigger a recompile cycle on any project that has had one or more of its binary dependencies changed rather than just on projects that have their source code changed.
In any event, I appreciate the feedback and the free QA services ๐
@Steve
Anytime ๐
Steve,
I intend to utilize most of the tools you used in Summer of NHib (The best software development screencast I have seen) including the UnitTest Utility Library. MySQL is the database I use, so does the UniTest Utility support this. I see that DatabaseClientType supported are OleDBClient, OracleClient and SqlClient.
Cheers.
@Abdishukri:
Thanks for the feedback — it nice to hear that you are finding value in the content.
Re: the direct support for MySQL, the question is really more about the underlying NDbUnit library atop which my own Unit Test Utility sits. And that (presently) supports only MS SQL Server and MS OleDB datasources — even the Oracle support (as of right now) will actually throw a NotImplementedException if you try to set it in my Unit Test Utility right now since its not yet fully implemented in NDbUnit.
As a committer to the NDbUnit project, I can report that I have nearly completed the native Oracle support and that ‘native’ MySQL support isn’t on the radar screen right now for the following reason: the intent of providing the OleDB support was precisely to try to implicitly cover all the ‘other’ DBs that are out there without having to cover each of them ‘explicitly’.
Even though the MS OleDB provider is almost never as ‘fast’, ‘efficient’, or ‘capable’ as using the DB vendor’s ‘native’ windows driver, for the very simple CRUD work that NDbUnit needs to perform its almost alway at least *workable*. Since MS’s OleDB provider can even sit in front of *any* ODBC-compliant data source, even if there isn’t an OleDB provider for MySQL, OleDb can be used in front of OBDC if that’s the only level at with MySQL provides a non-proprietary driver for Windows clients.
While I have no direct experience with MySQL short of having installed it about 3 years ago to briefly investigate its spatial data support, I’m pretty certain that you can use the OleDB client setting in the Unit Test Utility (which effectively just passes this setting on to NDbUnit) and then do either of the following….
NDbUnit –> OleDb Client –> MySQL OleDB driver –> My SQL DB
-or-
NDbUnit –> OleDb Client –> MS OleDb driver for ODBC –> MySQL ODBC driver –> My SQL DB
…either of which *should* allow you to properly connect to the MySQL DB using the utility.
Best of luck and let me know how you make out — I’d be curious to know your results.
Hi Steve,
I tried both of your provider setup suggestions and I get the same outcome.
First the SaveTestDatabase function works on both and TestData.xml is created correctly, but both fail on the TestFixtureSetUp with similar error which I think is related to how the Dataset is used to generate sql syntax. Any feedback on this and here is the error from a direct MySQL OLEDB provider setup:
Exploring DALTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
MbUnit 2.4.2.355 Addin
Found 1 tests
TestCase ‘[fixture-setup] TestFixtureSetUp’
failed: [1]: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘1 * from [acc_payable]’ at line 1
System.Data.OleDb.OleDbException
Message: [1]: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘1 * from [acc_payable]’ at line 1
Source: System.Data
StackTrace:
at System.Data.OleDb.OleDbCommand.PrepareCommandText(Int32 expectedExecutionCount)
at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
at System.Data.OleDb.OleDbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.OleDb.OleDbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.FillSchemaInternal(DataSet dataset, DataTable datatable, SchemaType schemaType, IDbCommand command, String srcTable, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.FillSchema(DataSet dataSet, SchemaType schemaType, IDbCommand command, String srcTable, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.FillSchema(DataSet dataSet, SchemaType schemaType)
at Microdesk.Utility.UnitTest.DatabaseUnitTestBase.ValidateSchemaAgainstDatabase(String schemaFilename)
at Microdesk.Utility.UnitTest.DatabaseUnitTestBase.DatabaseFixtureSetUp(Boolean ignoreSchemaDifferences)
at Microdesk.Utility.UnitTest.DatabaseUnitTestBase.DatabaseFixtureSetUp()
D:\WorkSpace\Daryeel\DALTest\Class1.cs(52,0): at DALTest.Tests._TestFixtureSetup()
@Abdishukri:
I’d have to agree that this seems like an issue with the SQL syntax. I’m unfamiliar with MySQL internals — is there any tool sim to SQL Server Profiler where you can capture the SQL syntax being sent to the server? Maybe if we saw more about what’s being sent we could identify it better –?
Steve,
This is the SQL syntax sent to MySQL Server by DatabaseFixtureSetUp():
Select top 1 * from [acc_payable];
That statment is invalid in MySQL Server and it is generated by either your Unit test Utility or MbUnit. I wouldn’t mind to fix this if your Utility is generating this.
Cheers from Perth, Australia (hot 40c).
@Abdishukri:
There isn’t any actual SQL generated by either MbUnit or the Unit Test Utility *directly*; what’s actually going on is that MbUnit is invoking methods in the Unit Test Utility which in turn is invoking methods in the NDbUnit library and that in turn is creating the SQL that’s (finally!) sent to the database. The chain looks like this…
MbUnit –> Unit Test Util –> NDbUnit –> DB
I’m going to guess that this is a conflict between what NDbUnit generates as SQL when set to OleDb and what MySQL is expecting. Assuming that you have correctly set…
_databaseClientType = DatabaseClientType.OleDBClient;
…in the test fixture in order to tell my Util (and by proxy, NDbUnit) to use the OleDB provider, this is an issue that will have to be addressed within NDbUnit directly.
Sadly, this is actually ALSO my issue to address even though its within the NDbUnit library since that’s an OSS project for which I am pretty much the only remaining contributor right now ๐
I am already in the process of adding explicit support for Oracle to the library and so I can add MySQL support as well, but could you point me to some kind of spec that identifies where within MySQL its support query syntax deviates from the SQL-92 specification so that I could get an idea of how much it differs from the standard (to get an idea of how much work it would be to support it directly)?
Steve,
MySQL seems to follow SQL-92, but where deviates I found this link: ftp://ftp.eenet.ee/arhiiv/mysql/doc/en/Differences_from_ANSI.html
I hope this is what you need and let me know if I can help.
Cheers,
@Abdishukri:
I’m looking into it now; at first glance it appears that this problem is b/c NDbUnit is attempting to pass a statement that begins with ‘Select 1 *…” and MySQL balks at that syntax since the way it looks like you constrain return rows in MySQL is with a LIMIT clause rather than a ROWCOUNT as is the case with SQLServer.
It rather appears to me that due to this kind of difference in the structure of the SQL statements accepted by MySQL, an actual variant of explicit support for MySQL is going to be needed in NDbUnit before it will (properly) support that DB platform.
This may or may not be a significant task (depending on the magnitude of other seemingly minor differences between supported sytax of SQL statements in MySQL). I’m uncertain how soon I can get to this, but I will absolutely put it on my list of to-do items for NDbUnit once I’m done integrating the Oracle direct support (which is my present focus for the project).
Stay tuned to my blog and I will certainly post here once the updates are completed. Sorry I haven’t better news for you — if you’d like to submit a patch for the project adding MySQL support, I’ll gladly accept it as well of course ๐
[…] both for me as a library author and for users of the library to keep straight too.
I’m trying to use your utility based on the NHibernate videos, specifically the savedatabase and testfixturesetup. I’m unable to run the first step, SaveTestDatabase() of base class Microdesk.Utility.UnitTest.DatabaseUnitTestBase. The exception I’m getting is “System.ArgumentException: Keyword not supported: ‘unicode’..”. I have an Oracle database, is it because Oracle is not supported?
Thanks
Jean
@Jean Lacroix:
Yes, my utility basically sits on top of the NDbUnit library and merely provides convenience automation methods for its own internal methods. NDbUnit doesn’t presently support Oracle as a database target and so I don’t doubt that it isn’t working for you against Oracle.
The good news however is that I am actually also presently in charge of the NDbUnit project ( http://code.google.com/p/ndbunit ) and I am in the process of integrating a patch submitted by someone that introduces Oracle support to the library.
Once this is complete (probably another two weeks or so given other demands on my time) I will release an update to NDbUnit and a corresponding update to my own utility that works along with it properly.
So the good news = its in the works but the bad news = what you are attempting right now is essentially unsupported.
HTH,
-Steve B.
How is the Oracle support coming? I see there was a release on April 4th, 1.3.0, was the Oracle support released in this version as stated in the project mapping?
I’d like to use NDbUnit but am running an Oracle database.
Thanks!
@Sean:
Oracle Support is still in progress; the release of the version 1.3.0 code was actually to accommodate the inclusion of patches that I rec’d unexpectedly that introduced support for SQLLite and SQLCe.
I wanted to fold these patches into the trunk ASAP and make them available for others ASAP so I did this release with support for these DB targets even though the roadmap claimed Oracle support was supposed to be ‘next’.
With some luck, I will have Oracle support completed soon (unless someone else submits a patch to me that provides it first, in which case I will have Oracle support completed sooner ๐ )
Hello !
I have a small question concerning DB Persistance using mbUnit with your really cool UnitTest library !
I have a table with a column type timestamp.
When the insert are launched for a resync after a test this error occurs :
“… CANNOT INSERT EXPLICIT VALUE INTO TIMESTAMP …”
I tried to removed the timestamp field from the xsd schema, but after I have errors telling me that a parameters is missing.
How do you handle this column type with mbUnit ?
Tx you for you help ! And tx you for you websites !!!
SeeMe
Hi Steve:
I listend through the summer of nHibernat section of yours and I am extremely impress by the content that you have put together for all of us. I really appreciate and thanks for all the hard work that you have done. This is the best tutorials set that I have ever seen.
I have a question regardng Microdesk.Utility.UnitTest. I am new to ndbunit and nhibernate so please forgive me for asking me dumb questions.
After reading some of your postings and documentations, I realise tat ndbunit does not support oracle yet. But in this post, you have mentioned in this post that
” Even though the MS OleDB provider is almost never as โfastโ, โefficientโ, or โcapableโ as using the DB vendorโs โnativeโ windows driver, for the very simple CRUD work that NDbUnit needs to perform its almost alway at least *workable*. ”
So I tried connecting Oracle with OLEDB Provider while estabishing the Database.xsd file. But when my test runs and when it calls DatabaseFixtureSetUp() method, I get the following error message. I am not sure if I understand this post correctly or doing something wrong.
Could you provide some light to this problem? Thanks in advance.
TestCase ‘M:NdbUnitOledbProviderTest.NdbOracleSupportTests._TestFixtureSetup’ failed: Keyword not supported: ‘provider’.
System.ArgumentException: Keyword not supported: ‘provider’.
at System.Data.Common.DbConnectionOptions.ParseInternal(Hashtable parsetable, String connectionString, Boolean buildChain, Hashtable synonyms, Boolean firstKey)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Hashtable synonyms, Boolean useOdbcRules)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(String connectionString, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(String value)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
at Microdesk.Utility.UnitTest.DatabaseUnitTestBase.ValidateSchemaAgainstDatabase(String schemaFilename)
at Microdesk.Utility.UnitTest.DatabaseUnitTestBase.DatabaseFixtureSetUp(Boolean ignoreSchemaDifferences)
at Microdesk.Utility.UnitTest.DatabaseUnitTestBase.DatabaseFixtureSetUp()
C:\Source\NHibernate\TUTORIALS\Summer of Nhibernate Session 14 Code\NdbUnitOledbProviderTest\NdbOracleSupportTests.cs(24,0): at NdbUnitOledbProviderTest.NdbOracleSupportTests._TestFixtureSetup()
@ThinkHex:
Thanks for the positive feedback; I’m glad to hear that you were able to get value out of the content.
Could you either post the code (of the test that’s throwing the exception) or ZIP the whole thing up and e-mail to me (sbohlen AT gmail.com) so I can take a look at it for you?
-Steve B.
[…] (required) Mail (will not be published) (required) Website. See the photo galleries: Click Here …Unhandled Exceptions Blog Archive UnitTest Utility …Jean Lacroix Says: I’m trying to use your utility based on the NHibernate videos, specifically the […]
Hi, I really appreciate the summer of nHibernate series. It has taught me a lot, I really like the way that you have covered the whole process of building an environment. I am in session 3 and in attempting to build I get:
The name ‘DatabaseFixtureSetup’ does not exist in the current context
Everything seemed ok prior to inheriting from Microdesk.Utility.UnitTest.DatabaseUnitTestBase, but I could be wrong.
Any ideas?
@Paul:
Try DatabaseFixtureSetUp();
It’s case-sensitive yOU kNOW