Unit testing with LLBLGen

Posts   
 
    
NickD
User
Posts: 224
Joined: 31-Jan-2005
# Posted on: 03-Aug-2005 18:14:00   

Anyone doing any unit testing specifically with LLBLGen? I'm excited by the idea of unit testing, but have read both sides of the "does it really help" arguments. One that I heard from Paul Wilson (on this podcast http://www.polymorphicpodcast.com) for why he doesn't use it is that unit testing of databases is difficult. Now I can think of reasons why I agree and disagree with him, but all my reasons are untested simple_smile . So, anyone have any input?

BTW - The guy who does that podcast also interviewed Thona from Entitybroker. Maybe you should give your two cents, Frans.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 04-Aug-2005 10:32:15   

NickD wrote:

Anyone doing any unit testing specifically with LLBLGen? I'm excited by the idea of unit testing, but have read both sides of the "does it really help" arguments. One that I heard from Paul Wilson (on this podcast http://www.polymorphicpodcast.com) for why he doesn't use it is that unit testing of databases is difficult. Now I can think of reasons why I agree and disagree with him, but all my reasons are untested simple_smile . So, anyone have any input?

Unit testing of database related code isn't difficult, you just have to set it up right. I have 2 databases for unittesting: one for writes (and refetches to test the writes) / deletes and one for fetching. The fetching database is static, no data is inserted there, just fetches are executed (in all kind of ways). The write/delete database is special made for unit-testing. It has 1:1 relations, and all other kind of nasty setups you can run into (it's pretty simple actually, not that much tables). Every table has a GUID, a testid which is the ID of the testrun (which is created when the unittests start). There is a single proc which gets the ID and removes all data with that testid.

So when I start the write tests, I create a GUID, all tests run and at teardown, the proc runs. Pretty simple.

I use the unittests to test user cases, not api interfaces. Initially unit-tests are developed to test api interfaces. So unittests are the tests for making sure the api does what it should do. So when you change something in the code, you run the tests again and the tests will tell you if the api still does what it should do or not.

I don't use unittests that way, as I find writing unittests for that a waste of time: they don't tell me the api WORKS, they only tell me the method called won't break under irrational parameters. calling format c: /u /y as a process works too, but only once, so what's the value of knowing that simple_smile .

Writing user cases is IMHO different: you think of ways how users would use the API and you test these usages with a unittest. This tests the collaboration of various methods with eachother to form a single feature.

Unittesting has another great feature: it's a standarized way of writing your tests and they can be run in a standard way. Every test is atomic, which is great, as you don't fall into the trap of having a big testapplication which has all kinds of global stuff which can ruin a test without you knowing it. I had such a testprogram but it becomes a big mess after a while. I'm glad I moved to unittesting a while ago.

Another great thing is that if a user has a problem, you can write a unittest to reproduce the problem. If the test succeeds, something else is a problem, but you have again a user case test added to your collection. So it's always good to keep these.

BTW - The guy who does that podcast also interviewed Thona from Entitybroker. Maybe you should give your two cents, Frans.

Roy Osherove interviewed me about agile stuff a while ago (over skype) but the sound quality was poor he said so he won't create a podcast from it. Oh well, I think unittesting is OK, but let's not overreact. It helps with testing what you wrote but only as far as the unittest's quality. If you forget to implement a test for a given case, you might leave in a bug.

I also think that refactoring is overrated. Refactoring isn't free, it costs a lot of time in some cases and won't make your software better in some cases. You'd better think through what you're going to implement TWICE before proceeding. So if you're not refactoring a lot, unittesting isn't that important as well.

For library developers, unittesting is of course important, but it's part of the overall testing. I also have visual tests, so I fetch a complicated prefetch path and bind it to a grid and see if the right rows are loaded and shown. You can't avoid these and unittests are useless in these kind of things.

Frans Bouma | Lead developer LLBLGen Pro
NickD
User
Posts: 224
Joined: 31-Jan-2005
# Posted on: 04-Aug-2005 16:03:49   

First off, thanks for such a thurough response! I hoped you'd have a good testing scenario set up simple_smile

Otis wrote:

Unit testing of database related code isn't difficult, you just have to set it up right. I have 2 databases for unittesting: one for writes (and refetches to test the writes) / deletes and one for fetching. The fetching database is static, no data is inserted there, just fetches are executed (in all kind of ways). The write/delete database is special made for unit-testing. It has 1:1 relations, and all other kind of nasty setups you can run into (it's pretty simple actually, not that much tables). Every table has a GUID, a testid which is the ID of the testrun (which is created when the unittests start). There is a single proc which gets the ID and removes all data with that testid.

Am I correct in understanding that your database test is there in order to test any changes you make to LLBLGen functionality? I guess what I'm getting at is that if you were in my shoes, would you write your database tests to test the functionality of LLBLGen, or would you write tests to, like you say, test possible user scenarios where they are registering students in classes or taking attendance. I wouldn't consider testing LLBLGen functionality because my assumption is that it's perfect wink So, my tests would simply test my data model structure and the effects of CRUD operations on other data parts.

Otis wrote:

I use the unittests to test user cases, not api interfaces. Initially unit-tests are developed to test api interfaces. So unittests are the tests for making sure the api does what it should do. So when you change something in the code, you run the tests again and the tests will tell you if the api still does what it should do or not.

I don't use unittests that way, as I find writing unittests for that a waste of time: they don't tell me the api WORKS, they only tell me the method called won't break under irrational parameters. calling format c: /u /y as a process works too, but only once, so what's the value of knowing that simple_smile .

Writing user cases is IMHO different: you think of ways how users would use the API and you test these usages with a unittest. This tests the collaboration of various methods with eachother to form a single feature.

I agree. I guess I hadn't thought too much about it yet, in terms of what kinds of parameters to use, but I like your ideas.

Otis wrote:

Another great thing is that if a user has a problem, you can write a unittest to reproduce the problem. If the test succeeds, something else is a problem, but you have again a user case test added to your collection. So it's always good to keep these.

This is what I see as the largest benefit. I have several windows that due to multiple enhancements and bug fixes by multiple programmers, I'm afraid to touch anything for fear of breaking something else. I know I'm not unique in this, so unit tests at least seem like they could be the beginnins of helping to at least releave some of that fear.

Thanks again for your thurough response.

mattsmith321 avatar
Posts: 146
Joined: 04-Oct-2004
# Posted on: 05-Aug-2005 19:56:42   

NickD wrote:

Am I correct in understanding that your database test is there in order to test any changes you make to LLBLGen functionality? I guess what I'm getting at is that if you were in my shoes, would you write your database tests to test the functionality of LLBLGen, or would you write tests to, like you say, test possible user scenarios where they are registering students in classes or taking attendance. I wouldn't consider testing LLBLGen functionality because my assumption is that it's perfect wink So, my tests would simply test my data model structure and the effects of CRUD operations on other data parts.

That's the approach that we are going with smile We aren't doing anything to test our DAL since it is all LLBL code, but we do have some tests that we run against our business layer to verify that we are getting correct responses from some of our more complicated functions. I see not having to test the DAL as yet another benefit of LLBL!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 07-Aug-2005 11:23:25   

NickD wrote:

First off, thanks for such a thurough response! I hoped you'd have a good testing scenario set up simple_smile

Otis wrote:

Unit testing of database related code isn't difficult, you just have to set it up right. I have 2 databases for unittesting: one for writes (and refetches to test the writes) / deletes and one for fetching. The fetching database is static, no data is inserted there, just fetches are executed (in all kind of ways). The write/delete database is special made for unit-testing. It has 1:1 relations, and all other kind of nasty setups you can run into (it's pretty simple actually, not that much tables). Every table has a GUID, a testid which is the ID of the testrun (which is created when the unittests start). There is a single proc which gets the ID and removes all data with that testid.

Am I correct in understanding that your database test is there in order to test any changes you make to LLBLGen functionality?

Yes, and to test user cases, so both testing if I wrote functionality correctly, and if it keeps on working when a bugfix is made.

I guess what I'm getting at is that if you were in my shoes, would you write your database tests to test the functionality of LLBLGen, or would you write tests to, like you say, test possible user scenarios where they are registering students in classes or taking attendance. I wouldn't consider testing LLBLGen functionality because my assumption is that it's perfect wink So, my tests would simply test my data model structure and the effects of CRUD operations on other data parts.

I'd test my own code. simple_smile My code isn't perfect, though when you test your own code and it doesn't work because of a bug in LLBLGen Pro, you'll run into it anyway. simple_smile

So, focus on your own functionality to write, test user cases of your own code and check if you've done the right thing. simple_smile If you've to test every 3rd party's code as well, you'll need another 24 hours in a day! simple_smile

Otis wrote:

Another great thing is that if a user has a problem, you can write a unittest to reproduce the problem. If the test succeeds, something else is a problem, but you have again a user case test added to your collection. So it's always good to keep these.

This is what I see as the largest benefit. I have several windows that due to multiple enhancements and bug fixes by multiple programmers, I'm afraid to touch anything for fear of breaking something else. I know I'm not unique in this, so unit tests at least seem like they could be the beginnins of helping to at least releave some of that fear.

That's one of the core goals of unittesting: to CHECK if something broke after a change in the code simple_smile

the other goal is to write up front a system, completely tested, with mock objects, to test out if it WILL work. After the tests succeed, you replace the mocks with real code and you have your tests already. Though that's deep TDD simple_smile

Frans Bouma | Lead developer LLBLGen Pro
BlueCell avatar
BlueCell
User
Posts: 83
Joined: 12-Jul-2004
# Posted on: 12-Nov-2005 23:46:21   

Otis wrote:

I use the unittests to test user cases, not api interfaces. Initially unit-tests are developed to test api interfaces. So unittests are the tests for making sure the api does what it should do. So when you change something in the code, you run the tests again and the tests will tell you if the api still does what it should do or not.

I don't use unittests that way, as I find writing unittests for that a waste of time: they don't tell me the api WORKS, they only tell me the method called won't break under irrational parameters. calling format c: /u /y as a process works too, but only once, so what's the value of knowing that simple_smile .

Writing user cases is IMHO different: you think of ways how users would use the API and you test these usages with a unittest. This tests the collaboration of various methods with eachother to form a single feature.

Sorry to bring up this old thread, but I just wanted to know something: does this mean you have build UML Use Cases aswell before every test? Just curious...

BC

fred_uk
User
Posts: 1
Joined: 09-Jul-2007
# Posted on: 09-Jul-2007 14:53:33   

A quick question on the subject of LLBLGen and Unit Testing.

Are there any unit test templates available that would allow the LLBLGen generated Data Access tier to be tested against a database/data model to ensure that they are synchronised?? In other words, to check/ensure that the data access tier is an exact representation of the structure of a certain database.

I've had a look around, but can't seem to find much on this topic. It would be really useful if -for example- you want to check the structural integrity of a database on a regular basis (ideally through continuous integration builds).

Cheers, Fred wink

gs_ham
User
Posts: 4
Joined: 19-Jun-2007
# Posted on: 10-Jul-2009 23:26:21   

I am just reading/researching TDD and other Agile concepts and this was my first question when looking into unit test. Do I have to write tests to verify that my O/R Mapper is doing what it is supposed to do?

It doesnt make sense to unit test the generated code IMO so we are saving our unit test efforts for any complex logic in our business layer. (Which is not very much might I add).

BTW, Frans you rock!!

Krish
User
Posts: 91
Joined: 02-Jan-2008
# Posted on: 11-Mar-2012 13:48:35   

Hi, I am using asp.net mvc 3 and unity D.I. container and DAL generated from Adapter two class template. I am passing IDataAccessAdapter to the controller ctor. I have mapped in the Unity container, IDataAccessAdapter to DataAccessAdapter. But at run time there is an error: Unity is not able to instantiate an instance of DataAccessAdapter. It looks like DataAccessAdapter has other dependencies and this is why the error is occuring. How do I get this to work?

I am using LLBLGen Pro 2.6 final, C#, Adapter 2 class template.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 12-Mar-2012 16:41:46   

Yes a couple of LLBLGen Runitme linraries. Please check the DBSpecific project for the referenced dlls.

Krish
User
Posts: 91
Joined: 02-Jan-2008
# Posted on: 13-Mar-2012 00:54:07   

I have referenced all the required dlls. Besides if I new up DataAccessAdapter it works, so it has to be something else. In unity this is what I am doing: container.RegisterType<IDataAccessAdapter, DataAccessAdapter>();

Please note, Unity has been setup correctly through NuGet. Also I have tested with simpler classes and interfaces and it works.

Stack Trace:

[InvalidOperationException: The type String cannot be constructed. You must configure the container to supply this value.] Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.GuardTypeIsNonPrimitive(IBuilderContext context, SelectedConstructor selectedConstructor) +273 Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.PreBuildUp(IBuilderContext context) +356 Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +262 Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlanCreatorPolicy.CreatePlan(IBuilderContext context, NamedTypeBuildKey buildKey) +187 Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +221 Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +262 Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +232 Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +90 BuildUp_Monpix.DAL.DatabaseSpecific.DataAccessAdapter(IBuilderContext ) +198 Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42 Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +309 Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +262 Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +232 Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +90 BuildUp_Monpix41.Controllers.HomeController(IBuilderContext ) +192 Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42 Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +309 Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +262 Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +377

[ResolutionFailedException: Resolution of the dependency failed, type = "Monpix41.Controllers.HomeController", name = "(none)". Exception occurred while: while resolving.

Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.

At the time of the exception, the container was:

Resolving Monpix41.Controllers.HomeController,(none) Resolving parameter "da" of constructor Monpix41.Controllers.HomeController(SD.LLBLGen.Pro.ORMSupportClasses.IDataAccessAdapter da) Resolving Monpix.DAL.DatabaseSpecific.DataAccessAdapter,(none) (mapped from SD.LLBLGen.Pro.ORMSupportClasses.IDataAccessAdapter, (none)) Resolving parameter "connectionString" of constructor Monpix.DAL.DatabaseSpecific.DataAccessAdapter(System.String connectionString, System.Boolean keepConnectionOpen, SD.LLBLGen.Pro.ORMSupportClasses.SchemaNameUsage schemaNameUsageSetting, System.String schemaNameToUse) Resolving System.String,(none) ] Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable1 resolverOverrides) +440 Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name, IEnumerable1 resolverOverrides) +45 Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides) +43 Microsoft.Practices.Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides) +56 Unity.Mvc3.UnityDependencyResolver.GetService(Type serviceType) +127 System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +51

Thanks.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 13-Mar-2012 07:30:24   

I'm not expert in Unity, but from info out there it seems that it tries to instantiate with the ctor with the maximum number of parameters. Try this:

IUnityContainer myContainer = new UnityContainer();
myContainer.RegisterType<IDataAccessAdapter, DataAccessAdapter>(new InjectionConstructor());

using (var adapter = myContainer.Resolve<IDataAccessAdapter>())
{
     ...
}

At least it works for me.

David Elizondo | LLBLGen Support Team
Krish
User
Posts: 91
Joined: 02-Jan-2008
# Posted on: 14-Mar-2012 01:54:44   

Hi David,

Thanks very much for that. It works! Passing new InjectionConstructor() to the RegisterType method does the trick.

Other thing I want to know is the life time of the DataAccessAdapter object. Should we use the LifetimeManager when registering types?

I see you are using the "using statement", but I am doing it as follows:

private readonly IDataAccessAdapter _daa;

////constructor injection
public SearchController(IDataAccessAdapter daa)
{
 if (daa == null)
   {
      throw new ArgumentNullException("data adapter");
   }
    this._daa = daa;
}


Then in a action method, something like:

totalRecords = (int)_daa.GetDbCount(fields, relPre, null, false);

 _daa.FetchTypedList(fields, combinedResults, relPre, 0, sorter, false, null, pageNumber, 10); 


etc.

I do not close the adapter connection or set the adapter (_daa in above example) to null so that it will get garbage collected.

In above example, when will the adpater get disposed of or will it lead to memory leaks etc. Or does it get disposed of by virtue of the containing controller (SearchController in above example) being garbage collected?

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 14-Mar-2012 11:28:08   

It will get disposed of by virtue of the containing controller (SearchController in above example) being garbage collected. simple_smile

Krish
User
Posts: 91
Joined: 02-Jan-2008
# Posted on: 15-Mar-2012 02:51:26   

Hi Walaa, Thanks for clarifying that.

I have read there is a problem with the MVC 3 D.I. seam (IDependencyResolver interface) http://mikehadlow.blogspot.com.au/2011/02/mvc-30-idependencyresolver-interface-is.html Do you think this will lead to memory leaks or not applicable in our case.

On a related matter, is it fair to say the LLBLGen self service template is baed on the Active Record pattern and the Adapter template is based on the table data gateway pattern?

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 16-Mar-2012 09:06:43   

I don't think holding an Adapter object in memory will ever lead to memory leaks.

As for the Design Patterns, from what I have read about the definition of the Active Record Patern and the Table Data Gateway pattern.

You can safely say that SelfServicing is an Active Record Pattern. While the Adapter template set is not a Table Data Gateway pattern.