- Home
- General
- General Chat
Unit testing with LLBLGen
Joined: 31-Jan-2005
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 . 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.
Joined: 17-Aug-2003
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 . 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 .
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.
Joined: 31-Jan-2005
First off, thanks for such a thurough response! I hoped you'd have a good testing scenario set up
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 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 .
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.
Joined: 04-Oct-2004
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 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 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!
Joined: 17-Aug-2003
NickD wrote:
First off, thanks for such a thurough response! I hoped you'd have a good testing scenario set up
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 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. 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.
So, focus on your own functionality to write, test user cases of your own code and check if you've done the right thing. If you've to test every 3rd party's code as well, you'll need another 24 hours in a day!
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
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
Joined: 12-Jul-2004
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 .
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
Joined: 09-Jul-2007
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
Joined: 19-Jun-2007
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!!
Joined: 02-Jan-2008
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.
Joined: 02-Jan-2008
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, IEnumerable
1 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.
Joined: 28-Nov-2005
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.
Joined: 02-Jan-2008
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?
Joined: 02-Jan-2008
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?
Joined: 21-Aug-2005
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.