<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6998972826668184815</id><updated>2012-01-31T12:37:21.098+01:00</updated><category term='Developer Testing'/><category term='SqlServer Integration Services'/><category term='Visual Studio'/><category term='Software Reviews'/><category term='Visual Studio Extensibility'/><category term='ADO Entity Framework'/><category term='Continuous Integration'/><category term='.NET design'/><category term='SQL Server Reporting Services'/><category term='WCF'/><category term='Office Business Applications'/><category term='.NET Coding'/><category term='Code Analysis'/><category term='Web App Development'/><category term='Software Development Organisation'/><category term='Winforms'/><category term='Pex'/><category term='Software Architecture'/><category term='Visual Studio Team System'/><category term='Testing'/><category term='ADO.NET'/><title type='text'>Application Development Chronicles</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>51</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-8344438863197198422</id><published>2008-12-22T22:24:00.005+01:00</published><updated>2008-12-23T09:30:05.642+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO Entity Framework'/><title type='text'>VISUG Event : Entity Framework &amp; WCF</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;Kurt Claeys gave a presentation about using the Entity Framework (EF) in a distributed scenario (Service oriented with WCF, Tight coupled Client-server) for the &lt;a href="http://www.visug.be/"&gt;Visug&lt;/a&gt; , the Belgian Visual Studio user group.&lt;br /&gt;&lt;br /&gt;His presentation was based on his personal research into the subject so he didn't gave immediately all the answers. Instead he showed us via concrete examples which difficulties he encountered during his endeavor.&lt;br /&gt;&lt;br /&gt;The reason for going N-tier and the way to achieve this were out of scope for the session but decoupling was the key concept he used to convey this requirement.&lt;br /&gt;&lt;br /&gt;After a very quick introduction into WCF and the EF, Kurt showed us the challenges you are confronted with if going this route and how WCF, EF or something else could provide a solution: Serialization of object graphs, contract sharing , … But the biggest hurdle in the current implementation seems to be change tracking.&lt;br /&gt;&lt;br /&gt;In EF, a special mechanism called the ObjectContext, keeps track of all the things you do with the entity instances you retrieve through the EF infrastructure. This means the entity identification , the relationships ….and also the changes you make to the entity instances or the relations between them. Without the objectContext the EF infrastructure cannot create the necessary insert/delete/update statements for your data store.&lt;br /&gt;&lt;br /&gt;Now a typical Service-oriented WCF service (cfr. 4 tenets of SOA ) is stateless in nature. This means that an operation that enables to retrieve an object graph through EF registers this action with the EF objectContext , but due to the nature of the service operation, the objectContext doesn’t stay around.&lt;br /&gt;&lt;br /&gt;Kurt showed in some examples what this means for us as a developer . He also tried to come up with solution candidates to the problems like for example re-fetching the entity again and using special functionality from the objectContext the apply the changes. It worked but only for a single entity instance without relations. If you would like to go further …you had to do it yourself. Another solution candidate was to re-attach the object and apply all the changes to the re-attached object . If you had relations….you get the picture: DIY was the common factor in the candidate solutions.&lt;br /&gt;&lt;br /&gt;There are some efforts in the EF community to give support of object change tracking in a distributed scenario but some of them are not active anymore and some are more research like efforts to look for solution.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Kurt concluded his presentation with what is coming in Vnext of EF , as told on PDC 2008.&lt;br /&gt;&lt;br /&gt;What I remember is that if you’re going to use EF in a distributed scenario you should clearly do your homework first and recognize the potential difficulties you about to face in your situation and come up with a strategy to solve them.&lt;br /&gt;&lt;br /&gt;Feel free to check the &lt;a class="postlink" href="http://www.visug.be/" target="_blank"&gt;Visug&lt;/a&gt; site if you want to browse through the presentation. Maybe &lt;a class="postlink" href="http://geekswithblogs.net/claeyskurt/Default.aspx" target="_blank"&gt;Kurt&lt;/a&gt; will also post his examples so you can try them out?&lt;br /&gt;&lt;br /&gt;What are your experiences with EF?&lt;br /&gt;&lt;br /&gt;Thanks for reading,&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-8344438863197198422?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/8344438863197198422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=8344438863197198422' title='36 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8344438863197198422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8344438863197198422'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/12/visug-event-entity-framework-wcf.html' title='VISUG Event : Entity Framework &amp; WCF'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>36</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-7912458193422873143</id><published>2008-11-28T09:32:00.005+01:00</published><updated>2008-11-28T09:53:21.913+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio Team System'/><title type='text'>VISUG event : VSTS 2010</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;Yesterday (27/11/2008) I attended the &lt;a href="http://www.visug.be/"&gt;VISUG &lt;/a&gt;presentation about Visual Studio team System 2010 ( previously known as Rosario) . Pieter Gheysens gave a focused presentation on some highlights based on the VSTS 2010 CTP (November 2008).&lt;br /&gt;VSTS 2010 is the third incarnation of the Visual Studio team System product portfolio. Since the previous versions (VSTS 2005, VSTS 2008) it has improved on several levels most notably on Source control management, build management ,test management and architecture &amp;amp; design.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Testing&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A new feature called Team System Lab Management. It is intended to ease up the configuration of testing environments using virtualization technology. (Not included in the CTP though) &lt;/li&gt;&lt;li&gt;A new standalone tool code-named “Camano” . This tool is intended to help you manage test plans; test configuration, functional test cases.&lt;br /&gt;A functional (manual) test execution assistant (not sure if this is part of Camano or something separate) that helps the tester to perform the tests. Pieter gave demo and showed the potential advantage of this tool. It namely can capture everything the tester was doing while executing the test. Not only the visible step through video capturing the screen but also the system information and the event happing in the application and optionally also the called methods and parameters. When a issue arising during testing the tester can link up with TFS and submit a bug item together with the captured execution data. The developer can use this information while investigating the issue (No more “it works fine on my machine” replies. A question from the audience quickly also showed that you should be careful whet you capture because every thing is stored inside TFS SQLserver databases. It was also not immediately how the test runner gathers all program execution information. Do we need to build a special instrumented version of the application when we give it to the functional tester? &lt;/li&gt;&lt;li&gt;Beside Web UI testing that was already available in previous version, a new test template named “coded Ui test” is available. Like in web UI testing, you can record your actions on a Winforms or WPF application and convert it into code and run it from the VS integrated test environment &lt;/li&gt;&lt;li&gt;There are also a some new test window s; The Impacted Tests view provides a list of tests that need to be run and which code changes are covered by each of the tests. The Code Changes view provides a list of code changes and which tests must be run in order to validate each of them. Of course the best practice is to run all test again when you change something but I guess this can be a time-saver in some cases.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Architecture&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;For better understanding code the code (for example the code base you get on your plate you never seen before and where you need to add or fix something) the new Architecture Explorer enables you to create a visual representation of existing code assets to give better insight , to see how things fit and work together. This can help you also in Impact analysis for changes. &lt;/li&gt;&lt;li&gt;There are several UML model templates available. The difference with the previous Class diagram for example (beside not being UML ) is the fact that it is not linked with code. An exception is the sequence diagram that you can reverse engineer from existing code. I don’t know if it is two way though. So the most models are merely a communication medium. Being integrated in VSTS saves you the use of Visio or enterprise architect. &lt;/li&gt;&lt;li&gt;A example of architectural constraint enforcement was also given. The Architecture Layer Diagram enables validation of code against a visual representation of the architecture. For example the presentation layer may not talk to class from the data access layer, you must pass a service layer. With the diagram you can hook up the class to be part of certain layer. &lt;/li&gt;&lt;li&gt;I still wonder how this all fits in the OSLO vision of model-driven development .&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Source control and management&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The most visually appealing demo was the branch visualization. VSTS now can depict branch and merge operation in a viewer ( a picture tells a 1000 words sometimes) &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;There some other topics on project management and the integration of TFS with Office Excel and Microsoft project , gated check in, workflow and parallel build management , ….and the ones I forgot . It other words there was to little time. I think Pieter have could spend an entire day showing new features of VSTS 2010. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;I guess download the CTP and start playing with it. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Also...a nice gesture from Microsoft , they made several books avaible for the attendees. You had to be quick to grab one. But anyway thank you Microsoft.&lt;br /&gt;&lt;br /&gt;There are some interesting session coming up so feel free to check out the &lt;a href="http://www.visug.be/"&gt;Visug web-site &lt;/a&gt;(Design principles, Entity Framework, WCF)&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-7912458193422873143?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/7912458193422873143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=7912458193422873143' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/7912458193422873143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/7912458193422873143'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/11/visug-event-vsts-2010.html' title='VISUG event : VSTS 2010'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-1166908427110010214</id><published>2008-10-17T09:44:00.012+02:00</published><updated>2008-10-17T14:17:22.072+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET design'/><title type='text'>Isolating your Dependency Injection Container</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;While searching for some background information about Dependency Injection Frameworks (aka Ioc containers ; ex. Windsor Castle, Unity, Spring.NET , StructureMap, etc) I stumbled on this &lt;a href="http://www.tavaresstudios.com/Blog/post/Announcing-The-IServiceLocator-interface.aspx"&gt;posting&lt;/a&gt; by Chris Tavares (Unity creator) regarding the creation of a isolation layer for DI containers.&lt;br /&gt;&lt;br /&gt;Because there are several DI containers available ,  the creation of an extra shield between your code and the DI container of your choice seems not a bad idea if you want to keep a maximum of freedom to swith from container to container somewhere in time. It could be that in the lifetime of an application another DI container might be more suitable for your problem at hand because of certain feature it has.&lt;br /&gt;&lt;br /&gt;This is made possible with a generic interface that makes up the operations you can call from a DI container. So your code, when it needs a service from a DI container, only works against this interface.  At application startup you  of course need to hook up a real DI Container implementation with its own configuration semantics.  For several DI containers ther are already adapters written that convert the generic API semantics to the DI container specific API calls.&lt;br /&gt;&lt;br /&gt;You call read about it and download the code from the &lt;a href="http://www.codeplex.com/CommonServiceLocator"&gt;codeplex site&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Maybe some code snippets to get your appetite perhaps started?&lt;br /&gt;&lt;br /&gt;In the following code snippet you see the creation of the Castle Windsor Container and the act of resolving an instance of a particular type. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                IWindsorContainer windsorContainer = CreateWindsorContainer();&lt;br /&gt;&lt;br /&gt;                ObjectCatalog.IMyObject obj = windsorContainer[typeof(ObjectCatalog.IMyObject)] as ObjectCatalog.IMyObject;&lt;br /&gt;&lt;br /&gt;                System.Console.WriteLine("Straight Windsor");&lt;br /&gt;                System.Console.WriteLine(obj.WhoAreYou());&lt;br /&gt;                System.Console.ReadLine();&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                System.Console.WriteLine(ex.Message);&lt;br /&gt;                System.Console.ReadLine();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static IWindsorContainer CreateWindsorContainer()&lt;br /&gt;        {&lt;br /&gt;            IWindsorContainer windsorContainer;&lt;br /&gt;            windsorContainer = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));&lt;br /&gt;            return windsorContainer;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The Castle Windsor config section looks like this&lt;br /&gt;&lt;br /&gt;ps: I'm using SyntaxHighLighter. The XML is not shown correctly. It always set to uppercase. I will need to look it to that. (Tips are welcome!)&lt;br /&gt;&lt;br /&gt;&lt;pre class="XML" name="code"&gt;&lt;br /&gt;&lt;?xml version="1.0"?&gt;&lt;br /&gt;&lt;configuration&gt;&lt;br /&gt; &lt;configSections&gt;&lt;br /&gt;    &lt;section&lt;br /&gt;          name="castle"&lt;br /&gt;          type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" /&gt;&lt;br /&gt;  &lt;/configSections&gt;&lt;br /&gt;  &lt;castle&gt;&lt;br /&gt;    &lt;components&gt;&lt;br /&gt;      &lt;component&lt;br /&gt;            id="idIMyObject"&lt;br /&gt;            service="ObjectCatalog.IMyObject, ObjectCatalog"&lt;br /&gt;            type="ObjectCatalog.MyObject, ObjectCatalog" /&gt;&lt;br /&gt;    &lt;/components&gt;&lt;br /&gt;  &lt;/castle&gt;&lt;br /&gt;&lt;/configuration&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Consequently your code is pretty heavily "connected" to the DI container implementation of Castle Windsor in variuos ways (code + config). Which isn't necessarly all bad because in the beginning of the project you choose Windsor for its abilities. But suppose you want (or you need ; consolidation, standardization , features , ...) to change to another DI container implementation&lt;br /&gt;&lt;br /&gt;Let's rewrite everything to the Microsoft P'n'P Unity DI container.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;&lt;br /&gt;  class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;&lt;br /&gt;                IUnityContainer unityContainer = CreateUnityContainer();&lt;br /&gt;&lt;br /&gt;                ObjectCatalog.IMyObject obj = unityContainer.Resolve&lt;ObjectCatalog.IMyObject&gt;();&lt;br /&gt;&lt;br /&gt;                System.Console.WriteLine("Straight Unity");&lt;br /&gt;                System.Console.WriteLine(obj.WhoAreYou());&lt;br /&gt;                System.Console.ReadLine();&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                &lt;br /&gt;                System.Console.WriteLine(ex.Message);&lt;br /&gt;                System.Console.ReadLine();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static IUnityContainer CreateUnityContainer()&lt;br /&gt;        {&lt;br /&gt;            IUnityContainer unityContainer;&lt;br /&gt;            unityContainer = new UnityContainer();&lt;br /&gt;            UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;&lt;br /&gt;            section.Containers["containerUnity"].Configure(unityContainer);&lt;br /&gt;            return unityContainer;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The config file for Unity for the example looks like this &lt;br /&gt;&lt;br /&gt;&lt;pre class="XML" name="code"&gt;&lt;br /&gt;&lt;?xml version="1.0"?&gt;&lt;br /&gt;&lt;configuration&gt;&lt;br /&gt; &lt;configSections&gt;&lt;br /&gt;    &lt;section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, &lt;br /&gt;             Microsoft.Practices.Unity.Configuration, Version=1.1.0.0,               &lt;br /&gt;             Culture=neutral, PublicKeyToken=31bf3856ad364e35"/&gt;&lt;br /&gt;  &lt;/configSections&gt;&lt;br /&gt;  &lt;unity&gt;&lt;br /&gt;    &lt;typeAliases&gt;&lt;br /&gt;      &lt;typeAlias alias="IMyObject" type="ObjectCatalog.IMyObject, ObjectCatalog"/&gt;&lt;br /&gt;         &lt;typeAlias alias="MyObject" type="ObjectCatalog.MyObject, ObjectCatalog"/&gt;&lt;br /&gt;        &lt;/typeAliases&gt;&lt;br /&gt;    &lt;containers&gt;&lt;br /&gt;      &lt;container name="containerUnity"&gt;&lt;br /&gt;        &lt;types&gt;&lt;br /&gt;          &lt;type type="IMyObject" mapTo="MyObject"/&gt;&lt;br /&gt;        &lt;/types&gt;&lt;br /&gt;      &lt;/container&gt;&lt;br /&gt;    &lt;/containers&gt;&lt;br /&gt;  &lt;/unity&gt;&lt;br /&gt;&lt;/configuration&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So besides the config information and the creation of the container, you also must change every location where you use the services of the DI container (that's usually more than than one like in the example:-)&lt;br /&gt;&lt;br /&gt;This is where the ServiceLocator comes in. It offers a generic way to talk to your DI container. The only implementation specifics are the config information and the creation of the container. So if you would need to change one day from one DI container to another, the changes kept to a minimum (although  changing a DI config info from one format to another is also not to be taken light. Maybe some XSL magic !)&lt;br /&gt;&lt;br /&gt;So how would the example look with the ServiceLocator?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;   class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            string ioc ="" ;&lt;br /&gt;            if (args.Length==0) &lt;br /&gt;                {ioc="Windsor";}&lt;br /&gt;            else&lt;br /&gt;                ioc=args[0] ;&lt;br /&gt;&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;&lt;br /&gt;                IServiceLocator myLocator = CreateLocator(ioc);&lt;br /&gt;&lt;br /&gt;                ObjectCatalog.IMyObject obj = myLocator.GetInstance&lt;ObjectCatalog.IMyObject&gt;();&lt;br /&gt;&lt;br /&gt;                System.Console.WriteLine("Service Locator");&lt;br /&gt;                System.Console.WriteLine(" Implementation : " + myLocator.GetType().ToString());&lt;br /&gt;                System.Console.WriteLine(obj.WhoAreYou());&lt;br /&gt;                System.Console.ReadLine();&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                &lt;br /&gt;               System.Console.WriteLine(ex.Message);&lt;br /&gt;               System.Console.ReadLine();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static IServiceLocator CreateLocator(string ioc)&lt;br /&gt;        {&lt;br /&gt;           IServiceLocator myLocator=null;&lt;br /&gt;           if (ioc=="Unity")&lt;br /&gt;            myLocator =  new UnityServiceLocator( CreateUnityContainer());&lt;br /&gt;           else if (ioc=="Windsor")&lt;br /&gt;            myLocator = new WindsorServiceLocator(CreateWindsorContainer());&lt;br /&gt;           else&lt;br /&gt;               throw new System.ArgumentException("Only Unity or Windsor are valid arguments");&lt;br /&gt;&lt;br /&gt;           return myLocator;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        private static IWindsorContainer CreateWindsorContainer()&lt;br /&gt;        {&lt;br /&gt;            IWindsorContainer windsorContainer;&lt;br /&gt;            windsorContainer = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));&lt;br /&gt;            return windsorContainer;&lt;br /&gt;        }&lt;br /&gt;           private static IUnityContainer CreateUnityContainer()&lt;br /&gt;        {&lt;br /&gt;            IUnityContainer unityContainer;&lt;br /&gt;            unityContainer = new UnityContainer();&lt;br /&gt;            UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;&lt;br /&gt;            section.Containers["containerUnity"].Configure(unityContainer);&lt;br /&gt;            return unityContainer;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So your code now makes use of a DI container generic API in order to hold on to a reference to a concrete DI Container implementation and also the calls to resolve dependencies or get instances from the DI container are written in a generic manner.&lt;br /&gt;The DI Container specific calls are made in the adapters (one for each concrete DI Container). So "GetInstance" will be translated to "Resolve" for the Unity Container. &lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-1166908427110010214?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/1166908427110010214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=1166908427110010214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1166908427110010214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1166908427110010214'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/10/isolating-your-dependency-injection.html' title='Isolating your Dependency Injection Container'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-4212713526909144180</id><published>2008-10-15T10:18:00.003+02:00</published><updated>2008-10-15T10:30:25.284+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web App Development'/><title type='text'>VISUG event : ASP.NET MVC</title><content type='html'>Hello&lt;br /&gt;&lt;br /&gt;Yesterday (14/oct/2008) , I attended a  presentation on ASP.NET Model-View–Controller (MVC) framework by &lt;a href="http://blog.maartenballiauw.be/"&gt;Maarten Balliauw &lt;/a&gt;that was organized by &lt;a href="http://www.visug.be/"&gt;VISUG &lt;/a&gt;( a Belgian .NET community). Last web development I did was in Netscape (Who?) LiveWire (What?) and I also some ASP (thus pre .NET era).  So I somehow skipped ASP.Net webforms but still followed it from the side-line. So this was an excellent opportunity to keep up-to-date with web-development.&lt;br /&gt;&lt;br /&gt;These are some points that I learned from the presentation:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ASP.NET MVC model is built on top of the ASP.NET framework.&lt;/li&gt;&lt;li&gt;It is something you have to install separately. &lt;/li&gt;&lt;li&gt;Fully integrated into Visual Studio&lt;/li&gt;&lt;li&gt;It is NOT a replacement for the current ASP.NET Webforms framework&lt;/li&gt;&lt;li&gt;The main goal is to allow programmers to clearly separate responsibilities according the MVC pattern. This clear separation of presentation logic, UI and the “rest” of the application is not only conceptually but also reflected in the code and project structure as created by the ASP.NET MVC project template&lt;/li&gt;&lt;li&gt;You can use ASP.NET infrastructure in an ASP.NET MVC application. Cohabitation of the webform way of working and the MVC way of working is possible. You can also use ASP.NET providers like membership and roles. You can also re-use ASP.NET session and so fort.&lt;/li&gt;&lt;li&gt;ASP.NET Server controls can be used as long as they don’t rely on the ViewState mechanism.&lt;/li&gt;&lt;li&gt;The filter-mechanism to create attributes to annotate parts of application tha can do reccuring activities for you (err handling, logging, etc)&lt;/li&gt;&lt;li&gt;A special routing mechanism for your requests is available.By default relies on a special convention of naming and structure to kick start the right controller. But you have the ability to intervene in this routing mechanism&lt;/li&gt;&lt;li&gt;Also the View parts must follow a convention (naming , folders)&lt;/li&gt;&lt;li&gt;You can more easily test the controller logic in “classic” unit test by controlling the dependencies with dependency injection and mocking frameworks. ASP.NET MVC plays along.&lt;/li&gt;&lt;li&gt;The “car and Motor-cycle” analogy : Webforms -&gt; car , ASP.NET -&gt; Motor-cycle. I guess it has to do with protection , speed, and so fort . Or with the fact that you can choose between them&lt;br /&gt;&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some questions I still have&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Still in CTP. Maarten thinks at PDC 2008 a beta will made available and a V1 will soon follow. But how it will be packaged, I’m not sure.&lt;/li&gt;&lt;li&gt;What about a MVP style implementation of ASP.NET webforms. Don’t you also get clean(er) separation, testability of presentation logic, understandability , etc ?&lt;/li&gt;&lt;li&gt;Is the Web Client Software factory from Patterns&amp;amp; practices a viable alternative?&lt;/li&gt;&lt;li&gt;In the examples Maarten showed I show a lot of in-line code in the View pages. So while server controls in webforms spit out the markup. Apparently I have to do the most your-self though Maarten mentioned some tools that can help you to alter the view rendering (Nhaml)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Some questions from the audience &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Can the controller be in separate assemblies? In the examples shown the relation between view and controller was very tight in the sense of the “actions” you can trigger from a view (so no reference dependencies). So in first line I would think this is a part of the presentation layer But according to Maarten there is someone who tampered with the routing mechanism to achieve this.&lt;/li&gt;&lt;li&gt;Hooking up Winforms in this MVC mechanisms:  It is called the ASP.NET MVC framework. It uses the System.Web namespace. So in the lower parts of the framework I guess all Http-stuff (get, post, etc). Maybe the MVP pattern is better suited? Has anyone used the Smart Client Software Factory?&lt;/li&gt;&lt;li&gt;There was also a question about comparison , I believe, between Monorail , classic Web forms and ASP.NET MVC.  I think this could be a valuable for many in order to have some “framework” to base a decision on what web development model to use (car-motorcycle analogy). One of the bullets is the presenation was : Not for everyone. So I guess there are some points to think about before embarking in a ASP.NET MVC implementation .&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I’m sure I forgot some things from the presentation. If you have any comments or would like to add some points (benefits or concerns) , feel free to drop a line.&lt;br /&gt;&lt;br /&gt;Visug has some more interesting sessions coming up ;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ASP.NET 3.5 sp1 novelties, &lt;/li&gt;&lt;li&gt;Rosario(VSTS 2010) , &lt;/li&gt;&lt;li&gt;Entity framework &amp;amp; WCF and &lt;/li&gt;&lt;li&gt;a session by Juval Lowy (hardcore WCF).&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-4212713526909144180?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/4212713526909144180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=4212713526909144180' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/4212713526909144180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/4212713526909144180'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/10/visug-event-aspnet-mvc.html' title='VISUG event : ASP.NET MVC'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-6264964451642986441</id><published>2008-08-20T10:08:00.014+02:00</published><updated>2008-08-21T11:43:02.103+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - Test Case 7</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;In this Pex test case I will investigate unit test on classes the have dependencies.( feel free to read the previous posts regarding this &lt;a href="http://appdevchronicles.blogspot.com/search/label/Pex"&gt;subject&lt;/a&gt;).&lt;br /&gt;I'll first start with how you would unit test this scenario without the help of Pex and afterwards I'll investigate how Pex might help.&lt;br /&gt;&lt;br /&gt;I have requirement to calculate the bonus a salesperson earns at the end of the year. The bonus depends on the sales he/she made this year and the year before. &lt;br /&gt;&lt;br /&gt;The rules are &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; The bonus amounts to 1% of the sales for that person&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If this year's sales is higher than 30000 €  AND ALSO this year's sales are higher than the Sales of the previuos year for that salesperson, an extra bonus is added of 250 €&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;A quick test analysis should result in following test cases&lt;br /&gt;&lt;table border="1"&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;currentYearSales greater or equal than 30000 €&lt;/td&gt; &lt;td&gt;Yes&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;br /&gt;&lt;td&gt;No&lt;/td&gt;&lt;br /&gt;&lt;td&gt;No&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;currentYearSales greater than LastYearSales &lt;/td&gt;&lt;br /&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;br /&gt;&lt;td&gt;No&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Base bonus (1% currentYearSales )&lt;/td&gt;&lt;br /&gt;&lt;td&gt;X&lt;/td&gt;&lt;br /&gt;&lt;td&gt;X&lt;/td&gt;&lt;br /&gt;&lt;td&gt;X&lt;/td&gt;&lt;br /&gt;&lt;td&gt;X&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Extra bonus (250€)&lt;/td&gt;&lt;td&gt;X&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;So three test cases would be sufficient for complete test coverage (last two test cases can be collapsed).&lt;br /&gt;&lt;br /&gt;Suppose you implements the rule in a bonus class and to know the sales amounts you have a Sales class that has appropriate methods to give you them. You've also encapsulated the retrival of these sales amounts inside the bonus class method that calculates the bonus.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public class Bonus&lt;br /&gt;    {&lt;br /&gt;         public double CalculateForEmployee(uint EmployeeId)&lt;br /&gt;        {&lt;br /&gt;         double baseBonusPercentage = 1;&lt;br /&gt;         double extraBonusAmount = 250;&lt;br /&gt;         uint minSalesForBonus = 30000;&lt;br /&gt;&lt;br /&gt;         Sales sales = new Sales();&lt;br /&gt;         uint currentYearSales = sales.CurrentYearSalesForEmployee(EmployeeId);&lt;br /&gt;         uint lastYearSales = sales.LastYearSalesForEmployee(EmployeeId);&lt;br /&gt;&lt;br /&gt;         double bonus = currentYearSales * (baseBonusPercentage / 100);&lt;br /&gt;         &lt;br /&gt;            if (currentYearSales &gt;= minSalesForBonus &amp;&amp; currentYearSales &gt; lastYearSales)&lt;br /&gt;                bonus += extraBonusAmount;&lt;br /&gt;&lt;br /&gt;            return System.Math.Floor(bonus);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public class Sales &lt;br /&gt;    {&lt;br /&gt;        public uint LastYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            //Could be a database call&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public uint CurrentYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            //Could be a database call&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Suppose you want to unit-test the method CalculateForEmployee in the Bonus class. The method calls into a Sales object to retrieve the sales for this year and the year before. Our code-under-test depends on another object to do its job. Nothing prevents you to write a standard unit test calling CalculateForEmployee.&lt;br /&gt;&lt;br /&gt; &lt;pre class="c#" name="code"&gt;&lt;br /&gt;     [TestMethod()]&lt;br /&gt;        public void CalculateForEmployeeTest()&lt;br /&gt;        {&lt;br /&gt;            Bonus target = new Bonus(); &lt;br /&gt;            uint EmployeeId = 0; //  ?&lt;br /&gt;            double expected = 0; // ?&lt;br /&gt;            double actual;&lt;br /&gt;            actual = target.CalculateForEmployee(EmployeeId);&lt;br /&gt;            Assert.AreEqual(expected, actual);&lt;br /&gt;        &lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But how do I know which EmployeeId to use and how do I know what the expected value for the bonus should be? In fact the method-under-test has dependencies we don't control in the unit test. The bonus class doesn't control the value of the sales. it's the responsibility of the sales class. As a matter a fact this situation isn't a pure unit test anymore. It's a unit integration test. So how can we control this dependency on the sales object and know in advance the EmployeeId and Sales amounts necessary for our method-under-test. Suppose a database is used to store sales information. We could setup a test database with all the necassary records for retrieving the sales for a particular sales employee. But this would still not classify our test as a unit test (only testing the rules for caculating the bonus). Also you must account for setting up three different test situation in the database.&lt;br /&gt;&lt;br /&gt;Rewritting our classes a little bit could helps us. Interfaces, &lt;a href="http://xunitpatterns.com/DfT%20Patterns.html"&gt;dependency injection &lt;/a&gt; and &lt;a href="http://xunitpatterns.com/Test%20Double%20Patterns.html"&gt;test doubles &lt;/a&gt; are techniques I will us to make the CalculateForEmployeeTest easier to test : knowing it advance what the sales amounts will be in order to assert the bonus.&lt;br /&gt;&lt;br /&gt;First we extract an interface from our Sales class&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public interface ISales&lt;br /&gt;    {&lt;br /&gt;        uint LastYearSalesForEmployee(uint EmployeeID);&lt;br /&gt;        uint CurrentYearSalesForEmployee(uint EmployeeID);&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;  public class Sales : ISales&lt;br /&gt;    {&lt;br /&gt;        public uint LastYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            //Could be a database call&lt;br /&gt;        }&lt;br /&gt;        public uint CurrentYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            //Could be a database call&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this example I'll use "manual" dependency injection (constructor injection) to demostrate the dependency injection principle.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public class Bonus&lt;br /&gt;    {&lt;br /&gt;        ISales mSalesdao;&lt;br /&gt;   &lt;br /&gt;     &lt;br /&gt;        public Bonus(ISales aSalesDao)&lt;br /&gt;        {&lt;br /&gt;            mSalesdao = aSalesDao;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public double CalculateForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            double baseBonusPercentage = 1;&lt;br /&gt;            double extraBonusAmount = 250;&lt;br /&gt;            uint minSalesForBonus = 30000;&lt;br /&gt;            double bonus;&lt;br /&gt;&lt;br /&gt;            uint currentYearSales = mSalesdao.CurrentYearSalesForEmployee(EmployeeID);&lt;br /&gt;            uint lastYearSales = mSalesdao.LastYearSalesForEmployee(EmployeeID);&lt;br /&gt;            &lt;br /&gt;            bonus = currentYearSales * (baseBonusPercentage / 100);&lt;br /&gt;            if (currentYearSales &gt;= minSalesForBonus &amp;&amp; currentYearSales &gt; lastYearSales)&lt;br /&gt;                bonus += extraBonusAmount;&lt;br /&gt;            &lt;br /&gt;            return System.Math.Floor(bonus);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So how does this help me in my unit test you might wonder? A test-double is a test-specific class that we will use in our unit tests so the code-under-test will not notice it that much. There are several variations of test-doubles. For example a test stub is an equivalent of the dependend class but gives "fixed answers" if we ask for something or does something in a pre-determined way.&lt;br /&gt;&lt;br /&gt;So instead of passing a real instance of the type Sales to the constructor of Bonus, I slip in a test stub when I write the unit tests. Because it gives fixed answers , I'll need a test stub for each test case.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public class SalesStub_CYSsmaller30000 : ISales&lt;br /&gt;    {&lt;br /&gt;       &lt;br /&gt;        public uint LastYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            return 29999;&lt;br /&gt;        }&lt;br /&gt;        public uint CurrentYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            return 29998;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class SalesStub_CYSgreater30000_CYSgreaterLYS : ISales&lt;br /&gt;    {&lt;br /&gt;        public uint LastYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            return 30001;&lt;br /&gt;        }&lt;br /&gt;        public uint CurrentYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            return 30002;&lt;br /&gt;        }&lt;br /&gt;      &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class SalesStub_CYSgreater30000_CYSsmallerLYS : ISales&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        public uint LastYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            return 30003;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public uint CurrentYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            return 30002;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The unit tests use these stubs to do their thing. I create a teststub that is appropriate for the test case and inject it into the constructor of bonus.&lt;br /&gt; &lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;        [TestMethod()]&lt;br /&gt;        public void CalculateForEmployee_Lys29999_cs29998_withStub()&lt;br /&gt;        {&lt;br /&gt;            ISales aSalesDao = new SalesStub_CYSsmaller30000();&lt;br /&gt;            Bonus target = new Bonus(aSalesDao); &lt;br /&gt;            uint EmployeeID = 0; // Dummy EmployeeID not important for this example&lt;br /&gt;            double expected = 299; //&lt;br /&gt;            double actual;&lt;br /&gt;            actual = target.CalculateForEmployee(EmployeeID);&lt;br /&gt;            Assert.AreEqual(expected, actual);     &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        [TestMethod()]&lt;br /&gt;        public void CalculateForEmployee_Lys30001_cs30002_WithStub()&lt;br /&gt;        {&lt;br /&gt;            ISales aSalesDao = new SalesStub_CYSgreater30000_CYSgreaterLYS();&lt;br /&gt;            Bonus target = new Bonus(aSalesDao); &lt;br /&gt;            uint EmployeeID = 0; // Dummy EmployeeID not important for this example&lt;br /&gt;            double expected = 550; //&lt;br /&gt;            double actual;&lt;br /&gt;            actual = target.CalculateForEmployee(EmployeeID);&lt;br /&gt;            Assert.AreEqual(expected, actual);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;       //and so&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Another implementation for test doubles is the use of a Mock framework. This utility dynamically create test-equivalent objects that are setup (expectations) through the framework facilities . I'll illustrate this with the help of &lt;a href="http://www.ayende.com/projects/rhino-mocks/downloads.aspx"&gt;Rhino.Mock&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;     [TestMethod()]&lt;br /&gt;       public void CalculateForEmployee_Lys29999_cs29998_withMock()&lt;br /&gt;        {&lt;br /&gt;             uint EmployeeID = 0; // Dummy EmployeeID not important for this test purpose&lt;br /&gt;&lt;br /&gt;            Rhino.Mocks.MockRepository mr = new Rhino.Mocks.MockRepository();&lt;br /&gt;            ISales salesDao = mr.CreateMock&lt;ISales&gt;();&lt;br /&gt;            Rhino.Mocks.Expect.Call(salesDao.LastYearSalesForEmployee(EmployeeID)).Return(29999);&lt;br /&gt;            Rhino.Mocks.Expect.Call(salesDao.CurrentYearSalesForEmployee(EmployeeID)).Return(29998);&lt;br /&gt;            mr.ReplayAll();&lt;br /&gt;&lt;br /&gt;            Bonus target = new Bonus(salesDao); &lt;br /&gt;          &lt;br /&gt;         &lt;br /&gt;            double expected = 299; &lt;br /&gt;            double actual;&lt;br /&gt;            actual = target.CalculateForEmployee(EmployeeID);&lt;br /&gt;            Assert.AreEqual(expected, actual);&lt;br /&gt;&lt;br /&gt;            mr.VerifyAll();&lt;br /&gt;&lt;br /&gt;           &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       [TestMethod()]&lt;br /&gt;       public void CalculateForEmployee_Lys30001_cs30002_WithMock()&lt;br /&gt;            {&lt;br /&gt;                uint EmployeeID = 0; // Dummy EmployeeID not important for this test purpose&lt;br /&gt;&lt;br /&gt;                Rhino.Mocks.MockRepository mr = new Rhino.Mocks.MockRepository();&lt;br /&gt;                ISales salesDao = mr.CreateMock&lt;ISales&gt;();&lt;br /&gt;                Rhino.Mocks.Expect.Call(salesDao.LastYearSalesForEmployee(EmployeeID)).Return(30001);&lt;br /&gt;                Rhino.Mocks.Expect.Call(salesDao.CurrentYearSalesForEmployee(EmployeeID)).Return(30002);&lt;br /&gt;                mr.ReplayAll();&lt;br /&gt;&lt;br /&gt;                Bonus target = new Bonus(salesDao); &lt;br /&gt;               &lt;br /&gt;               &lt;br /&gt;                double expected = 550; //&lt;br /&gt;                double actual;&lt;br /&gt;                actual = target.CalculateForEmployee(EmployeeID);&lt;br /&gt;                Assert.AreEqual(expected, actual);&lt;br /&gt;&lt;br /&gt;                mr.VerifyAll();&lt;br /&gt;            }&lt;br /&gt;      //and so on&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The use of a Mock framework doesn't force me to explicitly write numerous of test stubs.&lt;br /&gt;&lt;br /&gt;So where does Pex come in? For Pex to  do its job I'll need a parametrized unit test. This is a unit test that will take arguments. Consider it as a test refactoring thing. Things that are common in the unit test are extracted and put into separate method/function. Pex needs this setup because it will be in charge with generating "traditional" unit tests with test data values that it will determine during its exploration phase. These generated unit test will call the parametrized unit test , passing the necessary arguments.&lt;br /&gt;&lt;br /&gt;In our "mock" example we explicitly setup the mock for each unit test. In analogy with the parametrized unit test we need a parametrized Mock object (see Pex Tutorial).&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    [TestClass]&lt;br /&gt;    [PexClass]&lt;br /&gt;    public partial class BonusTest&lt;br /&gt;    {&lt;br /&gt;        [PexMethod]&lt;br /&gt;        [PexUseType(typeof(SalesPexMock))]&lt;br /&gt;        public void Calculate(ISales aSalesPexMock)&lt;br /&gt;        {&lt;br /&gt;            PexAssume.IsNotNull(aSalesPexMock);&lt;br /&gt;            &lt;br /&gt;            uint EmployeeID = 9999; //dummy , not important for our test&lt;br /&gt;            Bonus target = new Bonus(aSalesPexMock);&lt;br /&gt;            double result = target.CalculateForEmployee(EmployeeID);&lt;br /&gt;            PexValue.AddForValidation("result", result);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [PexMock]&lt;br /&gt;    public class SalesPexMock : ISales&lt;br /&gt;    {&lt;br /&gt;        public uint LastYearSalesForEmployee(uint aEmployeeID)&lt;br /&gt;        {&lt;br /&gt;            var call = PexOracle.Call(this);&lt;br /&gt;            uint lys = (uint)call.ChooseFrom("lastYearSales", new uint[] { 29999, 30000, 30001 });&lt;br /&gt;            PexValue.Add&lt;uint&gt;("lastYearSales", lys);&lt;br /&gt;            return lys;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public uint CurrentYearSalesForEmployee(uint EmployeeID)&lt;br /&gt;        {&lt;br /&gt;            var call = PexOracle.Call(this);&lt;br /&gt;            uint lys = (uint)call.ChooseFrom("CurrentYearSales", new uint[] {29999, 30000, 30001});&lt;br /&gt;            PexValue.Add&lt;uint&gt;("CurrentYearSales", lys);&lt;br /&gt;            return lys;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;Running the PexExplorartion on the PexMethod will result in three unit test being generated.&lt;br /&gt;&lt;br /&gt;&lt;pre class= "c#" name = "code"&gt;&lt;br /&gt;   [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(BonusTest))]&lt;br /&gt;        public void Calculate01()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            IPexOracleRecorder oracle = PexOracle.NewTest();&lt;br /&gt;            ((IPexOracleSessionBuilder)&lt;br /&gt;              (oracle.OnCall(0, "SalesPexMock.CurrentYearSalesForEmployee(UInt32)")))&lt;br /&gt;                .ChooseAt(0, "CurrentYearSales", (object)30000u);&lt;br /&gt;            ((IPexOracleSessionBuilder)&lt;br /&gt;              (oracle.OnCall(1, "SalesPexMock.LastYearSalesForEmployee(UInt32)")))&lt;br /&gt;                .ChooseAt(0, "lastYearSales", (object)30000u);&lt;br /&gt;            SalesPexMock salesPexMock = new SalesPexMock();&lt;br /&gt;            this.Calculate((ISales)salesPexMock);&lt;br /&gt;            global::Microsoft.Pex.Framework.PexValue.Generated.Validate("result", "300");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(BonusTest))]&lt;br /&gt;        public void Calculate02()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            IPexOracleRecorder oracle = PexOracle.NewTest();&lt;br /&gt;            ((IPexOracleSessionBuilder)&lt;br /&gt;              (oracle.OnCall(0, "SalesPexMock.CurrentYearSalesForEmployee(UInt32)")))&lt;br /&gt;                .ChooseAt(0, "CurrentYearSales", (object)29999u);&lt;br /&gt;            ((IPexOracleSessionBuilder)&lt;br /&gt;              (oracle.OnCall(1, "SalesPexMock.LastYearSalesForEmployee(UInt32)")))&lt;br /&gt;                .ChooseAt(0, "lastYearSales", (object)30000u);&lt;br /&gt;            SalesPexMock salesPexMock = new SalesPexMock();&lt;br /&gt;            this.Calculate((ISales)salesPexMock);&lt;br /&gt;            global::Microsoft.Pex.Framework.PexValue.Generated.Validate("result", "299");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(BonusTest))]&lt;br /&gt;        public void Calculate03()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            IPexOracleRecorder oracle = PexOracle.NewTest();&lt;br /&gt;            ((IPexOracleSessionBuilder)&lt;br /&gt;              (oracle.OnCall(0, "SalesPexMock.CurrentYearSalesForEmployee(UInt32)")))&lt;br /&gt;                .ChooseAt(0, "CurrentYearSales", (object)30001u);&lt;br /&gt;            ((IPexOracleSessionBuilder)&lt;br /&gt;              (oracle.OnCall(1, "SalesPexMock.LastYearSalesForEmployee(UInt32)")))&lt;br /&gt;                .ChooseAt(0, "lastYearSales", (object)29999u);&lt;br /&gt;            SalesPexMock salesPexMock = new SalesPexMock();&lt;br /&gt;            this.Calculate((ISales)salesPexMock);&lt;br /&gt;            global::Microsoft.Pex.Framework.PexValue.Generated.Validate("result", "550");&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Of course meanwhile you verified the test coverage results :-) in the Pex report or via the Visual Studio Test Coverage facility.&lt;br /&gt;&lt;br /&gt;So with the PexMock framework expectations for the indivudual unit test are setup , just like we did in our Rhino.Mock example. Of we had to help the Pex mock framework a little bit just like we did with the parametrized unit test.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks for reading. Of course your comments are most welcome.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ps: We already had complaints of Salespersons that find this bonus rule not fair. for example sales-persons that are above the minimum sales amount eligable for extra bonus but are not progressing , don't get it. Like wise someone who is progressing doesn't receive extra incentives.... :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-6264964451642986441?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/6264964451642986441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=6264964451642986441' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6264964451642986441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6264964451642986441'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/08/pex-test-case-7.html' title='Pex - Test Case 7'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-8258476559881453869</id><published>2008-08-11T11:57:00.008+02:00</published><updated>2008-08-20T10:19:13.982+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - test case 6 (revisited...again)</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I did some further test on &lt;a href="http://appdevchronicles.blogspot.com/2008/08/pex-test-case-6.html"&gt;test case 6&lt;/a&gt; . I removed all pex assumptions regarding the dates. This time Pex had no problem finding the test cases necessary for a complete block coverage.&lt;br /&gt;&lt;br /&gt;So the PUT states no assumptions regarding the dates;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt; [TestClass]&lt;br /&gt;    [PexClass(typeof(EmployeeServices))]&lt;br /&gt;    public partial class EmployeeServicesTest&lt;br /&gt;    {&lt;br /&gt;        [PexMethod()]&lt;br /&gt;        public void DeterminePensionContribution([PexAssumeUnderTest]EmployeeServices target, Employee aEmployee)&lt;br /&gt;        {&lt;br /&gt;           PexAssume.IsNotNull(aEmployee);&lt;br /&gt;           PexAssume.IsTrue(aEmployee.Salary &gt; 1400 &amp;&amp; aEmployee.Salary &lt; 10000);&lt;br /&gt;           PexAssume.IsTrue(aEmployee.TypeContract == Contract.FullTime || aEmployee.TypeContract == Contract.PartTime);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            PensionContribution result = target.DeterminePensionContribution(aEmployee);&lt;br /&gt;&lt;br /&gt;            PexValue.AddForValidation("BaseContribution", result.BaseContribution);&lt;br /&gt;            PexValue.AddForValidation("SupplementaryContribution", result.SupplementaryContribution);&lt;br /&gt;&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000)&lt;br /&gt;                Assert.IsTrue(result.BaseContribution == 80);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000)&lt;br /&gt;                Assert.IsTrue(result.BaseContribution == 135);&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000 &amp;&amp; aEmployee.Age &gt;= 45 &amp;&amp; aEmployee.ServiceYears &lt; 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 15);&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000 &amp;&amp; aEmployee.Age &lt; 45 &amp;&amp; aEmployee.TypeContract == Contract.FullTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 15);&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000 &amp;&amp; aEmployee.Age &gt;= 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 25);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp; aEmployee.Age &lt; 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5 &amp;&amp; aEmployee.TypeContract == Contract.FullTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 25);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp; aEmployee.Age &lt; 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5 &amp;&amp; aEmployee.TypeContract == Contract.PartTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 20);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp; aEmployee.Age &gt;= 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 20);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp; aEmployee.ServiceYears &lt; 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 30);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When you run Pex this time it generated none less than 11 unit tests. The generated DateTime value are constructed with the Ticks argument, so it no easy to see the actual dateTime. Actually the first time I run this Pex generated a tick value with a value larger than 32 bit. When running the generated unit tests, an exception was thrown specifying thant the tick value should be between the DateTime.Minvalue.Ticks and DateTimeValue.Maxvalue.Ticks. It seemed to me that i generated a 64-bit value.&lt;br /&gt;I haven't been able to reproduce this error though. May be it is one of the remarks in the release of this &lt;a href="http://research.microsoft.com/pex/downloads.aspx"&gt;version 0.6x&lt;/a&gt;. I'm running on Windows XP SP2!&lt;br /&gt;&lt;br /&gt;Nevertheless here are the generated unit tests.&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public partial class EmployeeServicesTest&lt;br /&gt;    {&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution01()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(1L);&lt;br /&gt;            employee = EmployeeFactory.Create&lt;br /&gt;                (2, "", "", default(DateTime), s0, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution02()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(1L);&lt;br /&gt;            employee = EmployeeFactory.Create&lt;br /&gt;                (2, "", "", default(DateTime), s0, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "25");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution03()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(1L);&lt;br /&gt;            employee = EmployeeFactory.Create&lt;br /&gt;                (2, "", "", default(DateTime), s0, 8192u, Contract.PartTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution04()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(647341024241516544L);&lt;br /&gt;            DateTime s1 = new DateTime(1L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "25");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution05()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(647341024241516544L);&lt;br /&gt;            DateTime s1 = new DateTime(1L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "15");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution06()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(647341024241516544L);&lt;br /&gt;            DateTime s1 = new DateTime(1L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.PartTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution07()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(1262076461318144L);&lt;br /&gt;            DateTime s1 = new DateTime(634715138118123520L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.PartTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "30");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution08()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(56623104001835008L);&lt;br /&gt;            DateTime s1 = new DateTime(634715138118123520L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "15");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution09()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(647341024241516544L);&lt;br /&gt;            DateTime s1 = new DateTime(634715138118123520L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "30");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution10()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(647341024241516544L);&lt;br /&gt;            DateTime s1 = new DateTime(1L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.PartTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "0");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContribution11()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee employee;&lt;br /&gt;            DateTime s0 = new DateTime(633532870975488000L);&lt;br /&gt;            DateTime s1 = new DateTime(126226978751643648L);&lt;br /&gt;            employee = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices employeeServices = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(employeeServices, employee);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "15");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When you investigate the coverage results for Visual Studio and the output from Pex, you will see that both confirm the 100% coverage result.&lt;br /&gt;&lt;br /&gt;Part of the Pex report , coverage section (click on picture for better view):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_GROsRPS-U-k/SKAUJ3Mdw3I/AAAAAAAAAO0/2uB9Qt3cz_I/s1600-h/PexCoverage.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SKAUJ3Mdw3I/AAAAAAAAAO0/2uB9Qt3cz_I/s400/PexCoverage.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5233204926672126834" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What about my "business" assumptions? Maybe it would be easier to incorporate them as pre-conditions in the code under test. For example Start date of the contract should be greater than  25/May/1968 in the setter method for Startdatecontract of our Employee class. Non-compliance would than result in an exception being thrown. how will pex cope with them?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks for reading. As always, feel free to comment.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-8258476559881453869?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/8258476559881453869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=8258476559881453869' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8258476559881453869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8258476559881453869'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/08/pex-test-case-6-revisitedagain.html' title='Pex - test case 6 (revisited...again)'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_GROsRPS-U-k/SKAUJ3Mdw3I/AAAAAAAAAO0/2uB9Qt3cz_I/s72-c/PexCoverage.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-9060853566346941027</id><published>2008-08-11T08:56:00.005+02:00</published><updated>2008-08-21T08:54:05.944+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - test case 6 (revisited)</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;In the previous &lt;a href="http://appdevchronicles.blogspot.com/2008/08/pex-test-case-6.html"&gt;case &lt;/a&gt;I tried to come up with a scenario where a method takes a "complex" type instead of primitive types like integers of booleans. The exercise didn't go as expected.  By the way , the latest downloadable version of &lt;a href="http://research.microsoft.com/research/downloads/Details/d2279651-851f-4d7a-bf05-16fd7eb26559/Details.aspx"&gt;Pex &lt;/a&gt;is 0.6.30728.0&lt;br /&gt;&lt;br /&gt;To see whether pex still works on a method with primitive types, I re-wrote the method as follows.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;  public PensionContribution DeterminePensionContribution2(&lt;br /&gt;             uint aSalary, &lt;br /&gt;             uint aAge, &lt;br /&gt;             uint aServiceYears, &lt;br /&gt;             Contract aTypeContract)&lt;br /&gt;        {&lt;br /&gt;            //no pre-codition checks ....&lt;br /&gt;&lt;br /&gt;            PensionContribution contribution = new PensionContribution();&lt;br /&gt;&lt;br /&gt;            if (aSalary &lt;= 3000)&lt;br /&gt;            {&lt;br /&gt;                if (aAge &lt; 45)&lt;br /&gt;                {&lt;br /&gt;                    if (aTypeContract == Contract.FullTime)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 15;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 0;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    if (aServiceYears &lt; 5)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 15;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 25;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                if (aAge &lt; 45)&lt;br /&gt;                {&lt;br /&gt;                    if (aServiceYears &lt; 5)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 135;&lt;br /&gt;                        contribution.SupplementaryContribution = 30;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        if (aTypeContract == Contract.FullTime)&lt;br /&gt;                        {&lt;br /&gt;                            contribution.BaseContribution = 135;&lt;br /&gt;                            contribution.SupplementaryContribution = 25;&lt;br /&gt;                        }&lt;br /&gt;                        else&lt;br /&gt;                        {&lt;br /&gt;                            contribution.BaseContribution = 135;&lt;br /&gt;                            contribution.SupplementaryContribution = 20;&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    if (aServiceYears &lt; 5)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 135;&lt;br /&gt;                        contribution.SupplementaryContribution = 30;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 135;&lt;br /&gt;                        contribution.SupplementaryContribution = 20;&lt;br /&gt;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;            return contribution;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The PUT method looks like this.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;      [PexMethod]&lt;br /&gt;        public void PUTDeterminePensionContribution(&lt;br /&gt;            [PexAssumeUnderTest]EmployeeServices target,&lt;br /&gt;            uint aSalary,&lt;br /&gt;            uint aAge,&lt;br /&gt;            uint aServiceYears,&lt;br /&gt;            Contract aTypeContract&lt;br /&gt;        )&lt;br /&gt;        {&lt;br /&gt;            PexAssume.IsTrue(aAge &gt; 18 &amp;&amp; aAge &lt; 75);&lt;br /&gt;            PexAssume.IsTrue(aServiceYears &gt; 0 &amp;&amp; aServiceYears &lt; 50);&lt;br /&gt;            PexAssume.IsTrue(aSalary &gt; 1400 &amp;&amp; aSalary &lt; 10000);&lt;br /&gt;            PexAssume.IsTrue(aTypeContract == Contract.FullTime || aTypeContract == Contract.PartTime);&lt;br /&gt;&lt;br /&gt;            PensionContribution result = target.DeterminePensionContribution&lt;br /&gt;                (aSalary, aAge, aServiceYears, aTypeContract);&lt;br /&gt;            PexValue.AddForValidation("BaseContribution", result.BaseContribution);&lt;br /&gt;            PexValue.AddForValidation("SupplementaryContribution", result.SupplementaryContribution);&lt;br /&gt;&lt;br /&gt;            if (aSalary &lt;= 3000)&lt;br /&gt;                Assert.IsTrue(result.BaseContribution == 80);&lt;br /&gt;            if (aSalary &gt; 3000)&lt;br /&gt;                Assert.IsTrue(result.BaseContribution == 135);&lt;br /&gt;            if (aSalary &lt;= 3000 &amp;&amp; aAge &gt;= 45 &amp;&amp; aServiceYears &lt; 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 15);&lt;br /&gt;            if (aSalary &lt;= 3000 &amp;&amp; aAge &lt; 45 &amp;&amp; aTypeContract == Contract.FullTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 15);&lt;br /&gt;            if (aSalary &lt;= 3000 &amp;&amp; aAge &gt;= 45 &amp;&amp; aServiceYears &gt;= 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 25);&lt;br /&gt;            if (aSalary &gt; 3000 &amp;&amp; aAge &lt; 45 &amp;&amp; aServiceYears &gt;= 5 &amp;&amp; aTypeContract == Contract.FullTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 25);&lt;br /&gt;            if (aSalary &gt; 3000 &amp;&amp; aAge &lt; 45 &amp;&amp; aServiceYears &gt;= 5 &amp;&amp; aTypeContract == Contract.PartTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 20);&lt;br /&gt;            if (aSalary &gt; 3000 &amp;&amp; aAge &gt;= 45 &amp;&amp; aServiceYears &gt;= 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 20);&lt;br /&gt;            if (aSalary &gt; 3000 &amp;&amp; aServiceYears &lt; 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 30);&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In no time Pex finds the test cases for full block coverage&lt;br /&gt;&lt;br /&gt; &lt;table border="1"&gt;&lt;tr&gt;&lt;td&gt;target&lt;/td&gt;&lt;td&gt;aSalary&lt;/td&gt;&lt;td&gt;aAge&lt;/td&gt;&lt;td&gt;aServiceYears&lt;/td&gt;&lt;td&gt;aTypeContract&lt;/td&gt;&lt;td&gt;BaseContribution&lt;/td&gt;&lt;td&gt;SupplementaryContribution&lt;/td&gt;&lt;td&gt;Summary/Exception&lt;/td&gt;&lt;td&gt;Error Message&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;FullTime&lt;/td&gt;&lt;td&gt;135&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;/tr&gt;    &lt;br /&gt;  &lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;FullTime&lt;/td&gt;&lt;td&gt;135&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;FullTime&lt;/td&gt;&lt;td&gt;135&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;FullTime&lt;/td&gt;&lt;td&gt;135&lt;/td&gt;&lt;td&gt;25&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;1532&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;FullTime&lt;/td&gt;&lt;td&gt;80&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;1532&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;FullTime&lt;/td&gt;&lt;td&gt;80&lt;/td&gt;&lt;td&gt;25&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;1532&lt;/td&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;FullTime&lt;/td&gt;&lt;td&gt;80&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;PartTime&lt;/td&gt;&lt;td&gt;135&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;1532&lt;/td&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;PartTime&lt;/td&gt;&lt;td&gt;80&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;PartTime&lt;/td&gt;&lt;td&gt;135&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;/tr&gt; &lt;/table&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So there is nothing "wrong" with the method under test.  The problem when you investigate the output window, lies maybe in the calculation of the "age" and "serviceYears" properties. &lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;00:00:00.0&gt; starting execution&lt;br /&gt;  00:00:00.0&gt; reflecting tests&lt;br /&gt;  00:00:00.3&gt; TestProject1&lt;br /&gt;    00:00:00.3&gt; EmployeeTest&lt;br /&gt;      00:00:00.3&gt; DeterminePensionContributionIntern(Employee)&lt;br /&gt;        &lt;boundary&gt; maxconstraintsolvertime - 1s (constraint solver time out after 1 seconds)&lt;br /&gt;        [execution]     4 runs&lt;br /&gt;        [execution]    15 runs&lt;br /&gt;        [test] (run 20) DeterminePensionContribution&lt;br /&gt;        [test] (run 21) DeterminePensionContribution&lt;br /&gt;        [execution]    21 runs, 49/81 blocks covered&lt;br /&gt;        [test] (run 25) DeterminePensionContribution&lt;br /&gt;        [execution]    29 runs, 49/81 blocks covered&lt;br /&gt;        [execution]    41 runs, 49/81 blocks covered&lt;br /&gt;        [modelsearch] could not flip 2 branches in a row&lt;br /&gt;        [execution]    50 runs, 49/81 blocks covered&lt;br /&gt;        [execution] imprecision at testingPEX.Employee.differenceInYears, offset 0x26&lt;br /&gt;        [modelsearch] could not flip 4 branches in a row&lt;br /&gt;        [execution]    77 runs (97,40% unique paths), 49/81 blocks covered&lt;br /&gt;        &lt;boundary&gt; timeout - 120s&lt;br /&gt;        &lt;boundary&gt; Timeout, 1 times&lt;br /&gt;        &lt;boundary&gt; MaxConstraintSolverTime, 60 times&lt;br /&gt;        [coverage] 49/81 block (60,49%)&lt;br /&gt;&lt;br /&gt;00:02:01.4&gt; [finished] 3 generated tests (0 failures), 00:02:01.3757768.&lt;br /&gt; -- 0 critical errors, 0 errors, 0 warnings.&lt;br /&gt;&lt;br /&gt;[reports] skipping report generation&lt;br /&gt;&lt;br /&gt;  EXPLORATION SUCCESS&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;monitored process exited with Success (0)&lt;br /&gt;finished&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pex needs to find dateTimes in order to test the conditions specified in the method. I used a helper method to calculate the years to date for the age and serviceyears:&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;   private uint differenceInYears(System.DateTime aDate1, System.DateTime aDate2)&lt;br /&gt;        {&lt;br /&gt;            //missing checks ....&lt;br /&gt;            //approximative&lt;br /&gt;            uint years = (uint)(aDate1.Year - aDate2.Year);&lt;br /&gt;            if (aDate1.Month == aDate2.Month)&lt;br /&gt;            {&lt;br /&gt;                if (aDate2.Day &lt; aDate1.Day) years = years - 1;&lt;br /&gt;            }&lt;br /&gt;            return years;&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Could it be the unsigned integer type declarations? Or are the assumptions wrongly formulated? Or both? What does "could not flip 2 branches in a row" mean?&lt;br /&gt;&lt;br /&gt;I'll try to do some more test around this. Feel free to comment!&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-9060853566346941027?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/9060853566346941027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=9060853566346941027' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/9060853566346941027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/9060853566346941027'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/08/pex-test-case-6-revisted.html' title='Pex - test case 6 (revisited)'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-9018928755457972245</id><published>2008-08-06T09:11:00.010+02:00</published><updated>2008-08-21T08:54:59.131+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - Test Case 6</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;In the previous Pex posts I used examples that used primitive types and/or strings as parameters for methods under test. In this post I will "test" Pex how it wil cope with a method that accepts a "complex type". This test scenario is similar to the case study in &lt;a href="http://appdevchronicles.blogspot.com/2008/07/pex-test-case-3.html"&gt;Pex - Test case 3&lt;/a&gt; except we don't work directly with primitive types a method parameters or return types. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Suppose the HR department asked you to include a new module in their Salary-application that will determine the contribution each employee has to make in a private pension fund. The salary administration uses the following desicion table.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_GROsRPS-U-k/SJlV0XgeJvI/AAAAAAAAAOU/AHRONS09EKw/s1600-h/pensiontable.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SJlV0XgeJvI/AAAAAAAAAOU/AHRONS09EKw/s400/pensiontable.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5231306800319309554" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;While analysing the table you conclude you can simplify the table to help you code this rule into c#.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_GROsRPS-U-k/SJlV6uT9M8I/AAAAAAAAAOc/v4AcjKUdKmk/s1600-h/pensiontablesimplified.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SJlV6uT9M8I/AAAAAAAAAOc/v4AcjKUdKmk/s400/pensiontablesimplified.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5231306909520049090" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You already have some classes in the application :&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public class Employee&lt;br /&gt;    {&lt;br /&gt;        //missing elementary checks in order to keep code concise....&lt;br /&gt;        public int EmployeeID { get; set; }&lt;br /&gt;        public string FirstName { get; set; }&lt;br /&gt;        public string LastName { get; set; }&lt;br /&gt;        private DateTime _BirthDate;&lt;br /&gt;        public DateTime BirthDate &lt;br /&gt;        { &lt;br /&gt;            get { return this._BirthDate; }&lt;br /&gt;            set { &lt;br /&gt;                this._BirthDate = value;&lt;br /&gt;                this.Age = differenceInYears(_BirthDate, DateTime.Now);&lt;br /&gt;                }&lt;br /&gt;        }&lt;br /&gt;        private DateTime _StartDateContract;&lt;br /&gt;        public DateTime StartDateContract { &lt;br /&gt;            get { return _StartDateContract; } &lt;br /&gt;            set { &lt;br /&gt;                _StartDateContract=value;&lt;br /&gt;                this.ServiceYears = differenceInYears(_StartDateContract, DateTime.Now);&lt;br /&gt;                 } }&lt;br /&gt;        public uint Salary { get; set; }&lt;br /&gt;        public Contract TypeContract { get; set; }&lt;br /&gt;        public uint Age { get; set; }&lt;br /&gt;        public uint ServiceYears { get; set; }&lt;br /&gt;        private uint differenceInYears(DateTime aDate1, DateTime aDate2)&lt;br /&gt;        {&lt;br /&gt;            //missing checks ....&lt;br /&gt;            //approximative&lt;br /&gt;            uint years = (uint)(aDate1.Year - aDate2.Year);&lt;br /&gt;            if (aDate1.Month == aDate2.Month)&lt;br /&gt;            {&lt;br /&gt;                if (aDate2.Day &lt; aDate1.Day) years = years - 1;&lt;br /&gt;            }&lt;br /&gt;            return years;&lt;br /&gt;        } &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public enum Contract&lt;br /&gt;    {&lt;br /&gt;        FullTime=0,&lt;br /&gt;        PartTime=1&lt;br /&gt;   }&lt;br /&gt;    &lt;br /&gt;    public struct PensionContribution&lt;br /&gt;    {&lt;br /&gt;        public uint BaseContribution{get;set;}&lt;br /&gt;        public uint SupplementaryContribution {get;set;}&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The rule has also been translated into c#. The method DeterminePensionContribution has a parameter of the type Employee as described in the above code snippet. The return type is the structure PensionContribution.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public class EmployeeServices&lt;br /&gt;    {&lt;br /&gt;        public PensionContribution DeterminePensionContribution(Employee aEmployee)&lt;br /&gt;        {&lt;br /&gt;            //no pre-condition checks .....&lt;br /&gt;&lt;br /&gt;            PensionContribution contribution = new PensionContribution ();&lt;br /&gt;&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000)&lt;br /&gt;            {&lt;br /&gt;                if (aEmployee.Age &lt; 45)&lt;br /&gt;                {&lt;br /&gt;                    if (aEmployee.TypeContract == Contract.FullTime)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 15;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 0;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    if (aEmployee.ServiceYears &lt; 5)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 15;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 80;&lt;br /&gt;                        contribution.SupplementaryContribution = 25;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                if (aEmployee.Age &lt; 45)&lt;br /&gt;                {&lt;br /&gt;                    if (aEmployee.ServiceYears &lt; 5)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 135;&lt;br /&gt;                        contribution.SupplementaryContribution = 30;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        if (aEmployee.TypeContract == Contract.FullTime)&lt;br /&gt;                        {&lt;br /&gt;                            contribution.BaseContribution = 135;&lt;br /&gt;                            contribution.SupplementaryContribution = 25;&lt;br /&gt;                        }&lt;br /&gt;                        else&lt;br /&gt;                        {&lt;br /&gt;                            contribution.BaseContribution = 135;&lt;br /&gt;                            contribution.SupplementaryContribution = 20;&lt;br /&gt;                        }   &lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    if (aEmployee.ServiceYears &lt; 5)&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 135;&lt;br /&gt;                        contribution.SupplementaryContribution = 30;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        contribution.BaseContribution = 135;&lt;br /&gt;                        contribution.SupplementaryContribution = 20;&lt;br /&gt;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;            return contribution;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        &lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;       &lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In a "test-after-you-code" scenario, you could use the desicion table to specify the values for actual for the different properties of a employee object that is being passed to the method under test. So 9 unit tests would be sufficient to touch all corners of the code.  &lt;br /&gt;&lt;br /&gt;A data-driven in test in Visual Studio is somewhat difficult because we are not dealing with simple datatype parameters. We could serialize the different instances and save it in string form into an external data source.&lt;br /&gt;&lt;br /&gt;Can Pex help generate the necessary unit test to fully test our code? &lt;br /&gt;&lt;br /&gt;Before heading to the PUT (Parameterized Unit Test) I would like to refer you to the &lt;a href="http://research.microsoft.com/pex/articles/pextutorial.pdf"&gt;Pex tutorial &lt;/a&gt; for more background information on setting up PexMethods.&lt;br /&gt;&lt;br /&gt;A new element in this case study is the use of a factory method to create our Employee object that will be used in the generated unit test. Pex will call this method with appropriate values that it has discovered during its exploration of the code in the generated unit tests. The cool part is that Pex will first complain about not being able to create a Employee object but then suggest a soulution for it : the Factoty method and generates it for us.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;  [PexFactoryClass]&lt;br /&gt;    public partial class EmployeeFactory&lt;br /&gt;    {&lt;br /&gt;        [PexFactoryMethod(typeof(Employee))]&lt;br /&gt;        public static Employee Create(&lt;br /&gt;            int i0,&lt;br /&gt;            string s0,&lt;br /&gt;            string s1,&lt;br /&gt;            DateTime dt0,&lt;br /&gt;            DateTime dt1,&lt;br /&gt;            uint ui0,&lt;br /&gt;            Contract c0&lt;br /&gt;        )&lt;br /&gt;        {&lt;br /&gt;          &lt;br /&gt;            Employee e0 = new Employee();&lt;br /&gt;            e0.EmployeeID = i0;&lt;br /&gt;            e0.FirstName = s0;&lt;br /&gt;            e0.LastName = s1;&lt;br /&gt;            e0.BirthDate = dt0;&lt;br /&gt;            e0.StartDateContract = dt1;&lt;br /&gt;            e0.Salary = ui0;&lt;br /&gt;            e0.TypeContract = c0;&lt;br /&gt;            return e0;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the generated unit test , this factory method is used as follows:&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;  [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_095656_001()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(626406282140467200L);&lt;br /&gt;            DateTime s1 = new DateTime(631149005309067264L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let's return to the PUT. The following PUT was based on a PexMethod that you can let the Visual Studio Pex integration build for you.&lt;br /&gt;During its explorartion Pex will try out different value for the properties of our Employee object. The assumptions should help Pex create reasonable test cases. The code in this example did not enforce them in order to keep the code somewhat limited in size.&lt;br /&gt;&lt;br /&gt;Because this method will be used for all generated unit test, the asserts have to be more general than you would normally do for a single unit test.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    [TestClass]&lt;br /&gt;    [PexClass(typeof(EmployeeServices))]&lt;br /&gt;    public partial class EmployeeServicesTest&lt;br /&gt;    {&lt;br /&gt;        [PexMethod(MaxConstraintSolverTime = int.MaxValue, Timeout = int.MaxValue)]&lt;br /&gt;        public void DeterminePensionContribution([PexAssumeUnderTest]EmployeeServices target, Employee aEmployee)&lt;br /&gt;        {&lt;br /&gt;           PexAssume.IsNotNull(aEmployee);&lt;br /&gt;          PexAssume.IsTrue(aEmployee.BirthDate &lt; new DateTime(1992, 1, 1) &amp;&amp; aEmployee.BirthDate &gt; new DateTime(1955, 1, 1));&lt;br /&gt;           PexAssume.IsTrue(aEmployee.StartDateContract &lt; DateTime.Now &amp;&amp; aEmployee.StartDateContract &gt; new DateTime(1968, 1, 1));&lt;br /&gt;           PexAssume.IsTrue(aEmployee.BirthDate &lt; aEmployee.StartDateContract);&lt;br /&gt;           PexAssume.IsTrue(aEmployee.Age &gt; 18);&lt;br /&gt;           PexAssume.IsTrue(aEmployee.Salary &gt; 1400 &amp;&amp; aEmployee.Salary &lt; 10000);&lt;br /&gt;           PexAssume.IsTrue(aEmployee.TypeContract == Contract.FullTime || aEmployee.TypeContract == Contract.PartTime);&lt;br /&gt;            &lt;br /&gt;&lt;br /&gt;            PensionContribution result = target.DeterminePensionContribution(aEmployee);&lt;br /&gt;&lt;br /&gt;            PexValue.AddForValidation("BaseContribution", result.BaseContribution);&lt;br /&gt;            PexValue.AddForValidation("SupplementaryContribution", result.SupplementaryContribution);&lt;br /&gt;&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000)&lt;br /&gt;                Assert.IsTrue(result.BaseContribution == 80);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000)&lt;br /&gt;                Assert.IsTrue(result.BaseContribution == 135);&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000 &amp;&amp; aEmployee.Age &gt;= 45 &amp;&amp; aEmployee.ServiceYears &lt; 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 15);&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000 &amp;&amp; aEmployee.Age &lt; 45 &amp;&amp; aEmployee.TypeContract == Contract.FullTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 15);&lt;br /&gt;            if (aEmployee.Salary &lt;= 3000 &amp;&amp; aEmployee.Age &gt;= 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 25);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp; aEmployee.Age &lt; 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5 &amp;&amp; aEmployee.TypeContract == Contract.FullTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 25);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp; aEmployee.Age &lt; 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5 &amp;&amp; aEmployee.TypeContract == Contract.PartTime)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 20);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp; aEmployee.Age &gt;= 45 &amp;&amp; aEmployee.ServiceYears &gt;= 5 )&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 20);&lt;br /&gt;            if (aEmployee.Salary &gt; 3000 &amp;&amp;  aEmployee.ServiceYears &lt; 5)&lt;br /&gt;                Assert.IsTrue(result.SupplementaryContribution == 30);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Running the Pex exploration several times (and after quite a while) I got results but no full coverage. Maybe the assumptions and/or asserts are not "pex-friendly"?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_GROsRPS-U-k/SJmbOtiProI/AAAAAAAAAOk/_Z-8FeUApws/s1600-h/pensionresults.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_GROsRPS-U-k/SJmbOtiProI/AAAAAAAAAOk/_Z-8FeUApws/s400/pensionresults.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5231383119211245186" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The generated unit tests only cover half of the code blocks. &lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;   public partial class EmployeeServicesTest&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_110101_000()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(619794039740301312L);&lt;br /&gt;            DateTime s1 = new DateTime(631148677322244096L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_110101_001()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(619794039740301312L);&lt;br /&gt;            DateTime s1 = new DateTime(631148677322244096L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "25");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_110121_002()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(619794039740301312L);&lt;br /&gt;            DateTime s1 = new DateTime(631148677322244096L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.PartTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_110200_003()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(626094836655304192L);&lt;br /&gt;            DateTime s1 = new DateTime(633479291125776385L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "30");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_110201_004()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(626094836655304192L);&lt;br /&gt;            DateTime s1 = new DateTime(633479291125776385L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "15");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_112335_000()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(609681269903603218L);&lt;br /&gt;            DateTime s1 = new DateTime(621044308151107616L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_112335_001()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(609681269903603218L);&lt;br /&gt;            DateTime s1 = new DateTime(621044308151107616L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "25");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_112422_002()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(609681269903603218L);&lt;br /&gt;            DateTime s1 = new DateTime(621044308151107616L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.PartTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "20");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_115647_003()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(627392712227689792L);&lt;br /&gt;            DateTime s1 = new DateTime(633479779357556736L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 8192u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "135");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "30");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(EmployeeServicesTest))]&lt;br /&gt;        public void DeterminePensionContributionEmployeeServicesEmployee_20080806_115718_004()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            Employee e0;&lt;br /&gt;            DateTime s0 = new DateTime(627392712227689792L);&lt;br /&gt;            DateTime s1 = new DateTime(633479779357556736L);&lt;br /&gt;            e0 = EmployeeFactory.Create(2, "", "", s0, s1, 1983u, Contract.FullTime);&lt;br /&gt;            EmployeeServices es0 = new EmployeeServices();&lt;br /&gt;            this.DeterminePensionContribution(es0, e0);&lt;br /&gt;            PexValue.Generated.Validate("BaseContribution", "80");&lt;br /&gt;            PexValue.Generated.Validate("SupplementaryContribution", "15");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_GROsRPS-U-k/SJmevLAjEDI/AAAAAAAAAOs/05vgErDHU2M/s1600-h/pensioncoverage.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SJmevLAjEDI/AAAAAAAAAOs/05vgErDHU2M/s400/pensioncoverage.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5231386975413669938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you have any suggestions to improve (re-factor) the test code or the code-under- test (test-friendliness), don't hesitate to drop a line.&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-9018928755457972245?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/9018928755457972245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=9018928755457972245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/9018928755457972245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/9018928755457972245'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/08/pex-test-case-6.html' title='Pex - Test Case 6'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_GROsRPS-U-k/SJlV0XgeJvI/AAAAAAAAAOU/AHRONS09EKw/s72-c/pensiontable.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-1620546771414544793</id><published>2008-07-31T10:30:00.011+02:00</published><updated>2008-08-21T08:55:42.347+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - test Case 5</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;This post is a continuation in a series of post about Pex, a test case generation tool from Microsoft research. This test scenario is a variation of test case 4. (sorry in advance for the table formatting , I still can not get it right :-(&lt;br /&gt;&lt;br /&gt;In the Pex tutorial on p37 you'll see an example of testing a Regular Expression. I didn't find one in the samples though. Too simple maybe? &lt;br /&gt;&lt;br /&gt;I'm no hero in regular Expressions. Thankfully there's a &lt;a href="http://regexlib.com/default.aspx"&gt;library &lt;/a&gt;loaded with regular expressions for every kind of application. The following regular expressing is for ensuring &lt;a href="http://regexlib.com/REDetails.aspx?regexp_id=31"&gt;strong passwords&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;br /&gt;&lt;tr&gt; &lt;br /&gt;&lt;td&gt;&lt;br /&gt;Expression&lt;/td&gt;&lt;td&gt; ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,8}$ &lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;br /&gt;Description &lt;/td&gt;&lt;td&gt;Password matching expression. Password must be at least 4 characters, no more than 8 characters, and must include at least one upper case letter, one lower case letter, and one numeric digit. &lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;br /&gt;Matches&lt;/td&gt;&lt;td&gt; asD1 | asDF1234 | ASPgo123 &lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;br /&gt;Non-Matches &lt;/td&gt;&lt;td&gt;asdf | 1234 | ASDF12345 &lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The code example where the regular expression is implemented in&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public class UserAccount&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        private string mPassword;&lt;br /&gt;&lt;br /&gt;        public string Password&lt;br /&gt;        {&lt;br /&gt;            get { return mPassword; }&lt;br /&gt;            set {&lt;br /&gt;                if (value == null)&lt;br /&gt;                    throw new System.ArgumentNullException("Please specify a valid password. (non-null)");&lt;br /&gt;                else&lt;br /&gt;                   {&lt;br /&gt;                    bool valid = RegularExpressions.Regex.IsMatch(value, @"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,8}$");&lt;br /&gt;                    if (valid)&lt;br /&gt;                        mPassword = value; &lt;br /&gt;                    else&lt;br /&gt;                        throw new System.ArgumentException("Please specify a Strong Password. ");&lt;br /&gt;                    }          &lt;br /&gt;                }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The pex method (keeping in mind the remarks in the comments from the previous &lt;a href="http://appdevchronicles.blogspot.com/2008/07/pex-test-case-4.html"&gt;test case&lt;/a&gt;: the invariant remark)&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;        [PexMethod()]&lt;br /&gt;        public void PasswordTest( string aPassword)&lt;br /&gt;        {&lt;br /&gt;            UserAccount target = new UserAccount();&lt;br /&gt;            target.Password = aPassword;&lt;br /&gt;&lt;br /&gt;            //no problem calling target.password several times, stays the same&lt;br /&gt;            Assert.IsTrue(target.Password != null);&lt;br /&gt;            Assert.IsTrue(target.Password.Length != 0);&lt;br /&gt;            Assert.IsTrue(target.Password.Length &gt;= 4);&lt;br /&gt;            Assert.IsTrue(target.Password.Length &lt;= 8);&lt;br /&gt;            Assert.IsTrue(RegularExpressions.Regex.IsMatch(target.Password, @"[A-Z]"));&lt;br /&gt;            Assert.IsTrue(RegularExpressions.Regex.IsMatch(target.Password, @"[a-z]"));&lt;br /&gt;            Assert.IsTrue(RegularExpressions.Regex.IsMatch(target.Password, @"[0-9]"));&lt;br /&gt;         &lt;br /&gt;&lt;br /&gt;            Assert.AreEqual(aPassword, target.Password);&lt;br /&gt;        }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We could do this without Pex of course. We have have to come up with several input values to trigger an exception (at least that is what we intended to program and now are verifying) and some test values for some "positive" tests. The equivalence class technique can surely help us out.&lt;br /&gt;&lt;br /&gt;Valid equivalence classes&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; bigger or equal than 4 characters &lt;/li&gt;&lt;br /&gt;&lt;li&gt; smaller or equal  than 8 characters&lt;/li&gt;&lt;br /&gt;&lt;li&gt; include at least one upper case letter&lt;/li&gt;&lt;br /&gt;&lt;li&gt; include at least one lower case letter&lt;/li&gt;&lt;br /&gt;&lt;li&gt; include at least one numeric digit&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Invalid equivalence classes&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; not null, non-existing&lt;/li&gt;&lt;br /&gt;&lt;li&gt; smaller than 4 characters &lt;/li&gt;&lt;br /&gt;&lt;li&gt; bigger  than 8 characters&lt;/li&gt;&lt;br /&gt;&lt;li&gt; no upper case letter&lt;/li&gt;&lt;br /&gt;&lt;li&gt; no lower case letter&lt;/li&gt;&lt;br /&gt;&lt;li&gt; no numeric digit&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;You normally start with searching a physical test case (password value) that covers all the valid equivalence classes and for each invalid equivalence class you should also make a test case (i.e. unit test as well). Try not to overlap any invalid equivalance classes so you can be sure that the forced invalidity throwed the exception.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;asDF1234 (covers all valid classes) &lt;/li&gt;&lt;br /&gt;&lt;li&gt;null (non existing)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Az1  (smaller than 4 chars)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ASDf12345 (etc)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;abcd1&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ABCD1&lt;/li&gt;&lt;br /&gt;&lt;li&gt;aBcDefGh&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;So 7 test cases should be enough ?&lt;br /&gt;&lt;br /&gt;What would Pex do? It should be as good as this (if not better , at least the tutorial almost implies so).&lt;br /&gt;If you would let the PexMethod work on the password setter method, you would get following results.&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;  &lt;tr&gt;&lt;th&gt;Run&lt;/th&gt;&lt;th&gt;aPassword&lt;/th&gt;&lt;th&gt;Summary/Exception&lt;/th&gt;&lt;th&gt;Error Messag&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;null&lt;/td&gt;&lt;td&gt;ArgumentNullException&lt;/td&gt;&lt;td&gt;Value cannot be null.&lt;br /&gt;Parameter name: Please specify a valid password. (non-null)&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;""""&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;\0&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;\u8000&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;\0\0&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;\0\n&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;\0\0\0&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;\n&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;\n\0&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;\0\u8000\u8000&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;21&lt;/td&gt;&lt;td&gt;\n\n&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;25&lt;/td&gt;&lt;td&gt;\u00062\u00f1\u0016\n\n&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;\09\u00ef\u0088f\r&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;75&lt;/td&gt;&lt;td&gt;\u8000\0\0\0\n\0&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;83&lt;/td&gt;&lt;td&gt;0\u0088o]O&lt;&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;    &lt;br /&gt;  &lt;tr&gt;&lt;td&gt;112&lt;/td&gt;&lt;td&gt;\u00062Oo\n\n&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;113&lt;/td&gt;&lt;td&gt;\u00062Oo\n&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;td&gt;114&lt;/td&gt;&lt;td&gt;\u00062Oo\n\n\n\n\n\n\n\n\n\n&lt;/td&gt;&lt;td&gt;ArgumentException&lt;/td&gt;&lt;td&gt;Please specify a Strong Password. &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Pex established 19 test cases. A little bit more if you would go for the manual approach. But are the test input values better? In terms of "readability" no. But Pex generated some input values that I wouldn't have thought of in the first place.&lt;br /&gt;&lt;br /&gt;The empty string was added in the Pex generated approach. In our manual exercise with didn't explicitly took that test case because this was implied in the "smaller than 4 chars" equivalence class. But again testing a little bit too much is maybe better (or saver) than testing too little.&lt;br /&gt;&lt;br /&gt;Also the Pex generated unit tests include non alfanumeric signs like * or /. Did I intended to do that with my expression? If not I have to re-write it. With my manual technique I "forget" them. So Pex went a little deeper than my test analysis.&lt;br /&gt;What about Escape characters such as "\n" (new line). pex included them and some tests passed. Was this the way I intended it? Were these the specs from the customer?&lt;br /&gt;&lt;br /&gt;The examples I used to get acquinted with Pex may seem academic but I believ show potential for a tool like Pex. How to use it in your day-to-day applications will take some time and study. And like the Pex FAQ already states : it is not Pex versus unit testing (or other forms of testing or QA assurance measures like code analysis for example). I hope the Pex team will (continue to) find sponsers within Microsoft to integrate it in the next releases of Visual studio. At least the pex team already took a &lt;a href="http://www.freepatentsonline.com/y2007/0033440.html"&gt;patent!&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-1620546771414544793?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/1620546771414544793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=1620546771414544793' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1620546771414544793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1620546771414544793'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/pex-test-case-5.html' title='Pex - test Case 5'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-6182852310665654787</id><published>2008-07-28T14:10:00.008+02:00</published><updated>2008-08-21T08:56:01.886+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - test case 4</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I've got one more test scenario for Pex. From comments on my previous post&lt;br /&gt;&lt;a href="http://appdevchronicles.blogspot.com/2008/07/pex-test-case-3.html"&gt;Case study 3&lt;/a&gt; I understood that the way I specified the PUT was not done correctly (though Pex generated the unit test methods I expected).&lt;br /&gt;&lt;br /&gt;A PUT should specify what the intended behaviour of the code under test should do. It should not do this like in a tradiotional unit test for a particular combination of test input but in a more general way.&lt;br /&gt;&lt;br /&gt;Sounds reasonable but I find some difficulity in writing them. I'll try to come with a "better" PUT this time.&lt;br /&gt;&lt;br /&gt;Our code under test is as follows (Sorry in advance for some bad formatting HTML tables later in the post.): &lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;      private string mCode;&lt;br /&gt;&lt;br /&gt;        public string Code&lt;br /&gt;        {&lt;br /&gt;            get { return mCode; }&lt;br /&gt;            set {&lt;br /&gt;                if (value == null ) &lt;br /&gt;                    {&lt;br /&gt;                    throw new System.ArgumentNullException("Please specify a valid code. (non-null)");    &lt;br /&gt;                    }&lt;br /&gt;               else if (value.Length &lt; 4)&lt;br /&gt;                {&lt;br /&gt;                    throw new System.ArgumentException("Please specify a valid code. (bigger than 3 characters.");&lt;br /&gt;                }&lt;br /&gt;                else if (value.Length &gt; 10)&lt;br /&gt;                {&lt;br /&gt;                    throw new System.ArgumentException("Please specify a valid code. (max 10 characters. including XYZ prefix) ");  &lt;br /&gt;                }&lt;br /&gt;                else if (value.StartsWith("XYZ") == false)&lt;br /&gt;                {&lt;br /&gt;                    throw new System.ArgumentException("Please specify a valid code (starting with XYZ - uppercase !) ");&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    this.mCode = value;&lt;br /&gt;                }&lt;br /&gt;              &lt;br /&gt;              }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With the comments for my PUT in mind , I created the following PUT:&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;       [PexMethod()]&lt;br /&gt;         public void CodeTest(string aCode)&lt;br /&gt;         {&lt;br /&gt;             measurement target = new measurement();&lt;br /&gt;             string actual;&lt;br /&gt;             target.Code = aCode;&lt;br /&gt;             actual = target.Code;&lt;br /&gt;             PexValue.AddForValidation("actual", actual);&lt;br /&gt;             if (( aCode != null) &amp;&amp; &lt;br /&gt;                 (aCode.Length &gt; 3) &amp;&amp;  &lt;br /&gt;                 (aCode.Length &lt;= 10) &amp;&amp; &lt;br /&gt;                 (aCode.StartsWith("XYZ")) ) &lt;br /&gt;                 PexAssert.IsTrue(actual == aCode);&lt;br /&gt;            &lt;br /&gt;         }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Running Pex on this PUT will result in several generated test cases.&lt;br /&gt;(Pex reporting option : Enable via Options/Pex/Reports)&lt;br /&gt;&lt;TABLE border="1"&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TH colSpan=4&gt;Parameter Values&lt;/TH&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TH&gt;Run&lt;/TH&gt;&lt;br /&gt;&lt;TH&gt;aCode&lt;/TH&gt;&lt;TH&gt;actual&lt;/TH&gt;&lt;TH&gt;Summary/Exception&lt;/TH&gt;&lt;/TR&gt;&lt;TR &gt;&lt;TD &gt;1&lt;/TD&gt;&lt;TD&gt;null &lt;/TD&gt;&lt;TD &gt;&amp;nbsp;&lt;/TD&gt;&lt;TD&gt;ArgumentNullException: &lt;PRE&gt;Value cannot be null.&lt;br /&gt;Parameter name: Please specify a valid code. (non-null)&lt;/PRE&gt;&lt;SPAN class=hint&gt;(testingPEX) &lt;/TD&gt;    &lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;2&lt;/TD&gt;&lt;TD&gt;"" &lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;&amp;nbsp;&lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;ArgumentException: Please specify a valid code. (bigger than 3 characters. (testingPEX) &lt;/TD&gt;&lt;br /&gt;    &lt;/TR&gt;&lt;br /&gt;&lt;TR&gt;&lt;br /&gt;&lt;TD&gt;3&lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;\0\0\0\0\0\0 &lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;&amp;nbsp;&lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;ArgumentException: Please specify a valid code (starting with XYZ - uppercase !) (testingPEX) &lt;/TD&gt;&lt;br /&gt;    &lt;/TR&gt;&lt;br /&gt;&lt;TR &gt;&lt;br /&gt;&lt;TD &gt;4&lt;/TD&gt;&lt;br /&gt;&lt;TD &gt;new string('\0', 14) &lt;/TD&gt;&lt;br /&gt;&lt;TD &gt;&amp;nbsp;&lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;ArgumentException: Please specify a valid code. (max 10 characters. including XYZ prefix) (testingPEX) &lt;/TD&gt;&lt;br /&gt;    &lt;/TR&gt;&lt;br /&gt;&lt;TR&gt;&lt;br /&gt;&lt;TD&gt;5&lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;XYZZZZZ &lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;XYZZZZZ &lt;/TD&gt;&lt;br /&gt;&lt;TD&gt;&amp;nbsp;&lt;/TD&gt;&lt;br /&gt;    &lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;&lt;br /&gt;Of course we first need to specify the expected exceptions (Pex will suggest these for you !) :&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Add attribute [PexAllowedExceptionFromAssembly(typeof(ArgumentNullException), "testingPEX")]&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Add attribute [PexAllowedExceptionFromAssembly(typeof(ArgumentException), "testingPEX")]&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The generated unit tests look like this : &lt;br /&gt;&lt;pre class = "c#" name="code"&gt;&lt;br /&gt;  public partial class measurementTest&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void CodeTestString_20080728_141020_005()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.CodeTest("XYZZZZZ");&lt;br /&gt;            PexValue.Generated.Validate("actual", "XYZZZZZ");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [ExpectedException(typeof(ArgumentNullException))]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void CodeTestString_20080728_143541_000()&lt;br /&gt;        {&lt;br /&gt;            this.CodeTest((string)null);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [ExpectedException(typeof(ArgumentException))]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void CodeTestString_20080728_143620_001()&lt;br /&gt;        {&lt;br /&gt;            this.CodeTest("");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [ExpectedException(typeof(ArgumentException))]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void CodeTestString_20080728_143620_002()&lt;br /&gt;        {&lt;br /&gt;            this.CodeTest("\0\0\0\0\0\0");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [ExpectedException(typeof(ArgumentException))]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void CodeTestString_20080728_143620_003()&lt;br /&gt;        {&lt;br /&gt;            this.CodeTest(new string('\0', 14));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you would verify the code coverage results in Visual Studio or via the Pex reporting option, you would see 100% Block coverage.&lt;br /&gt;&lt;br /&gt;Pex generated for us the strings to serve as input values. I don't know about you but I think this is pretty clever.&lt;br /&gt;&lt;br /&gt;Still I'm a little confused about the PUT I created. If I would delete all the pexAssert statements the exercise would still be the same for the generated unit tests.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;  [PexMethod()]&lt;br /&gt;         public void CodeTest(string aCode)&lt;br /&gt;         {&lt;br /&gt;             measurement target = new measurement();&lt;br /&gt;             string actual;&lt;br /&gt;             target.Code = aCode;&lt;br /&gt;             actual = target.Code;&lt;br /&gt;             PexValue.AddForValidation("actual", actual);  &lt;br /&gt;         }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-6182852310665654787?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/6182852310665654787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=6182852310665654787' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6182852310665654787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6182852310665654787'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/pex-test-case-4.html' title='Pex - test case 4'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-8133743926608869564</id><published>2008-07-25T11:45:00.008+02:00</published><updated>2008-08-21T08:57:58.095+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - Test case 3</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;This post is a continuation of previous posts. Feel free to check them out.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://appdevchronicles.blogspot.com/2008/07/starting-with-pex-program-exploration.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://appdevchronicles.blogspot.com/2008/07/pex-test-case-1.html"&gt;Case study 1&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://appdevchronicles.blogspot.com/2008/07/pex-test-case-2.html"&gt;Case study 2&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;In this example I base my example on the following rule:&lt;br /&gt;In our Order system we need to implement a validation rule to see whether we can accept an order or not. The criteria for acceptance where given to us (luckily) in the form of a decision table. There are three criteria ; an internal customer qualification scheme, the fact if the previous payments of the customer were usually on time and correct and the fact if the customer has sufficient credit possibilities.&lt;br /&gt;&lt;br /&gt;&lt;table  border="1" visible="true"&gt;&lt;br /&gt;&lt;tr&gt;&lt;td &gt;Cust-code&lt;/td&gt;&lt;td&gt;a&lt;/td&gt;&lt;td &gt;a&lt;/td&gt;&lt;td &gt;a&lt;/td&gt;&lt;td &gt;a&lt;/td&gt;&lt;td &gt;b&lt;/td&gt;&lt;td &gt;b&lt;/td&gt;&lt;td&gt;b&lt;/td&gt;&lt;td &gt;b&lt;/td&gt;&lt;td &gt;c&lt;/td&gt;&lt;td &gt;c&lt;/td&gt;&lt;td &gt;c&lt;/td&gt;&lt;td &gt;c&lt;/td&gt;&lt;td &gt;u&lt;/td&gt;&lt;td &gt;u&lt;/td&gt;&lt;td &gt;u&lt;/td&gt;&lt;td&gt;u&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td &gt;paymentsOK&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td &gt;CredietLimitOK&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;br /&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt; &lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;td &gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td &gt;AcceptOrder&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;br /&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;y&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;td &gt;n&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;    public enum CustomerType &lt;br /&gt;        { &lt;br /&gt;            U_Unknown = 0, &lt;br /&gt;            A_Status = 1, &lt;br /&gt;            B_Status = 2, &lt;br /&gt;            C_Status = 3 &lt;br /&gt;        } &lt;br /&gt;&lt;br /&gt;    public class OrderManager&lt;br /&gt;    {&lt;br /&gt;        public bool IsOrderToBeAccepted(CustomerType aClientType,  bool aGoodpaymentHistory,  bool aCreditSufficient) &lt;br /&gt;            { &lt;br /&gt;                bool orderAccept = false; &lt;br /&gt;                switch (aClientType) { &lt;br /&gt;                    case CustomerType.A_Status: &lt;br /&gt;                        if (aGoodpaymentHistory == true)  { &lt;br /&gt;                            orderAccept = true; &lt;br /&gt;                        }&lt;br /&gt;                       else&lt;br /&gt;                        {&lt;br /&gt;                            orderAccept = false;&lt;br /&gt;                        }&lt;br /&gt;                        break; &lt;br /&gt;                    case CustomerType.B_Status: &lt;br /&gt;                        if (aGoodpaymentHistory || aCreditSufficient) { &lt;br /&gt;                            orderAccept = true; &lt;br /&gt;                        } &lt;br /&gt;                        else { &lt;br /&gt;                            orderAccept = false; &lt;br /&gt;                        } &lt;br /&gt;                        break; &lt;br /&gt;                    case CustomerType.C_Status: &lt;br /&gt;                        orderAccept = true; &lt;br /&gt;                        break; &lt;br /&gt;                    default: &lt;br /&gt;                        orderAccept = false;  &lt;br /&gt;                        break; &lt;br /&gt;                } &lt;br /&gt;            return orderAccept; &lt;br /&gt;            } &lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With the help to the decsion table (thanks to the analyst :-), we can easily determine the test cases. &lt;br /&gt;There 2 test sitaution (different behaviours) we must account for : the order is accepted or is not accepted. So we need test cases that will result in a non-accepted order and we will need a test case that will result in an accepted order.  Those this mean two test cases (i.e. unit tests) are enough. There is always this "test completeness criterium". If this were a black-box test (we don't "see" the code) we could use a tool like &lt;a href="http://download.microsoft.com/download/f/5/5/f55484df-8494-48fa-8dbd-8c6f76cc014b/pict33.msi"&gt;Pict33 &lt;/a&gt; to propsose the combination of input values.&lt;br /&gt;&lt;br /&gt;In this "lab" test we both have design information (desicion table) and our code. The table in this case can help us enough. Each column will represent the values we will supply to the method under test. This means we’ll end up with 16 unit tests to achieve full coverage of our table (and hopefully also of our code). The unit test are there to verify if our “intentions” (i.e. implementing this method with the above rules)  were correctly transformed into code. Both test situations (order accepted / order not accepted) should normally be taken into account with these 16 test cases.&lt;br /&gt;&lt;br /&gt;We can write out our units tests :&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code" &gt;&lt;br /&gt;  [TestMethod()]&lt;br /&gt;        public void isOrderToBeAcceptedCase1()&lt;br /&gt;        {&lt;br /&gt;            OrderManager target = new OrderManager();&lt;br /&gt;            CustomerType ClientType = CustomerType.A_Status;&lt;br /&gt;            bool GoodpaymentHistory = false; &lt;br /&gt;            bool CreditSufficient = false; &lt;br /&gt;            bool expected = false; &lt;br /&gt;            bool actual;&lt;br /&gt;            actual = target.isOrderToBeAccepted(ClientType, GoodpaymentHistory, CreditSufficient);&lt;br /&gt;            Assert.AreEqual(expected, actual);&lt;br /&gt;           &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;       [TestMethod()]&lt;br /&gt;       public void isOrderToBeAcceptedCase2()&lt;br /&gt;       {&lt;br /&gt;           OrderManager target = new OrderManager();&lt;br /&gt;           CustomerType ClientType = CustomerType.A_Status;&lt;br /&gt;           bool GoodpaymentHistory = true;&lt;br /&gt;           bool CreditSufficient = false;&lt;br /&gt;           bool expected = false;&lt;br /&gt;           bool actual;&lt;br /&gt;           actual = target.isOrderToBeAccepted(ClientType, GoodpaymentHistory, CreditSufficient);&lt;br /&gt;           Assert.AreEqual(expected, actual);&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;        //and so one &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or we make a data-driven unit test.&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;      [DeploymentItem("TestProject1\\OrderAcceptanceCombinations.csv")]&lt;br /&gt;        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", &lt;br /&gt;            "|DataDirectory|\\OrderAcceptanceCombinations.csv",&lt;br /&gt;            "OrderAcceptanceCombinations#csv", DataAccessMethod.Sequential)]&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void DataDrivenIsOrderAccepted()&lt;br /&gt;        {&lt;br /&gt;            OrderManager target = new OrderManager();&lt;br /&gt;            CustomerType ClientType =  (CustomerType)(System.Convert.ToInt32(this.TestContext.DataRow["CustomerType"])) ;&lt;br /&gt;            bool GoodpaymentHistory = System.Convert.ToBoolean(this.TestContext.DataRow["PaymentsOK"]);&lt;br /&gt;            bool CreditSufficient= System.Convert.ToBoolean(this.TestContext.DataRow["CreditOK"]) ;&lt;br /&gt;            bool actual;&lt;br /&gt;            bool expected = System.Convert.ToBoolean(this.TestContext.DataRow["AcceptOrder"]) ;&lt;br /&gt;            actual = target.isOrderToBeAccepted(ClientType, GoodpaymentHistory, CreditSufficient);&lt;br /&gt;            Assert.IsTrue(actual == expected);&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Bottom line is we achieve acceptable code coverage. We can verify this with the Visual Studio Code Coverage facility of the test framework. &lt;br /&gt;&lt;br /&gt;In that respect we can actually reduce the number of test cases and still achieve full coverage. A technique we can use, is "collapsing" the desicion table. If we closely look at our rules, we can detect that several combinations should result in the same result. This means that some conditions are not taken into account (or don’t make sense) in some test cases. For example whether or not a customer with customer-type UnKnown has good creditRecords or even goodpayments records, it doesn’t matter. We don’t trust “Unknown” customers. We don’t allow an order for them! In order words we can reduce the number of test cases for 4 to 1&lt;br /&gt;&lt;br /&gt;If we do this exercise for the entire table , we should come up with the following decision table.&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;td&gt;Cust-code&lt;/td&gt;&lt;td&gt;a&lt;/td&gt;&lt;td&gt;a&lt;/td&gt;&lt;td&gt;b&lt;/td&gt;&lt;td&gt;b&lt;/td&gt;&lt;td&gt;b&lt;/td&gt;&lt;td&gt;c&lt;/td&gt;&lt;td&gt;u&lt;tr&gt;&lt;td&gt;paymentsOK&lt;/td&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CredietLimitOK&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AcceptOrder&lt;/td&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;This would mean we only need to 7 test cases to fully test our rule. Collapsing tables is powerful in terms of test case reduction but can also be “dangerous” while making an error in our reasoning. We could miss out on something. Better some more than too little, I think.&lt;br /&gt;&lt;br /&gt;How does Pex help me with testing this class method?&lt;br /&gt;&lt;br /&gt;Our pex trigger could look like this : &lt;br /&gt;&lt;pre class="c#" name="code" &gt;&lt;br /&gt;     [PexMethod()]&lt;br /&gt;        public void isOrderToBeAcceptedTest( CustomerType ClientType,&lt;br /&gt;                                            bool GoodpaymentHistory,&lt;br /&gt;                                           bool CreditSufficient)&lt;br /&gt;        {&lt;br /&gt;            OrderManager target = new OrderManager(); &lt;br /&gt;            bool actual;&lt;br /&gt;            actual = target.isOrderToBeAccepted(ClientType, &lt;br /&gt;                                                GoodpaymentHistory, &lt;br /&gt;                                                CreditSufficient);&lt;br /&gt;            PexValue.AddForValidation("actual",actual);&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This parameterized test should reach all our code if certain combination of input values is used. So Pex should be able to work with this test method.&lt;br /&gt;&lt;br /&gt;You can launch Pex from within Visual Studio 2008 C# by rightclicking the mouse (or pressing CTRL+F8). You will see a menu option ” Run Pex Exploration”. This will launch Pex in doing it’s job, running your code while generating the right combination of input values for each possible code path and then generating the code for all the test cases.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_GROsRPS-U-k/SInJoV-im-I/AAAAAAAAAMk/SoLkpBazhnk/s1600-h/pexresults.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SInJoV-im-I/AAAAAAAAAMk/SoLkpBazhnk/s400/pexresults.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5226930537471581154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is the same number of test cases as with our "manual" approach. So this looks pretty good.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;  public partial class OrderManagerTest&lt;br /&gt;    {&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(OrderManagerTest))]&lt;br /&gt;        public void isOrderToBeAcceptedTestCustomerTypeBooleanBoolean_20080725_143741_000()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.isOrderToBeAcceptedTest(CustomerType.U_Unknown, false, true);&lt;br /&gt;            PexValue.Generated.Validate("actual", "False");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(OrderManagerTest))]&lt;br /&gt;        public void isOrderToBeAcceptedTestCustomerTypeBooleanBoolean_20080725_143742_001()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.isOrderToBeAcceptedTest(CustomerType.A_Status, false, true);&lt;br /&gt;            PexValue.Generated.Validate("actual", "False");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(OrderManagerTest))]&lt;br /&gt;        public void isOrderToBeAcceptedTestCustomerTypeBooleanBoolean_20080725_143742_002()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.isOrderToBeAcceptedTest(CustomerType.A_Status, true, true);&lt;br /&gt;            PexValue.Generated.Validate("actual", "True");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(OrderManagerTest))]&lt;br /&gt;        public void isOrderToBeAcceptedTestCustomerTypeBooleanBoolean_20080725_143742_003()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.isOrderToBeAcceptedTest(CustomerType.B_Status, false, true);&lt;br /&gt;            PexValue.Generated.Validate("actual", "True");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(OrderManagerTest))]&lt;br /&gt;        public void isOrderToBeAcceptedTestCustomerTypeBooleanBoolean_20080725_143742_004()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.isOrderToBeAcceptedTest(CustomerType.B_Status, true, true);&lt;br /&gt;            PexValue.Generated.Validate("actual", "True");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(OrderManagerTest))]&lt;br /&gt;        public void isOrderToBeAcceptedTestCustomerTypeBooleanBoolean_20080725_143743_005()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.isOrderToBeAcceptedTest(CustomerType.B_Status, false, false);&lt;br /&gt;            PexValue.Generated.Validate("actual", "False");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(OrderManagerTest))]&lt;br /&gt;        public void isOrderToBeAcceptedTestCustomerTypeBooleanBoolean_20080725_143743_006()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.isOrderToBeAcceptedTest(CustomerType.C_Status, false, true);&lt;br /&gt;            PexValue.Generated.Validate("actual", "True");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We can check the coverage criterium within Visual Studio.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_GROsRPS-U-k/SInLPeBjVNI/AAAAAAAAAMs/B8Odj0YUJFA/s1600-h/FullCoverage.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_GROsRPS-U-k/SInLPeBjVNI/AAAAAAAAAMs/B8Odj0YUJFA/s400/FullCoverage.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5226932309158221010" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So Pex did an excellent work here. Of course the examples are somewhat academic and only use simple (primitive) types for arguments and/or return values. What about strings or complex types?&lt;br /&gt;&lt;br /&gt;My next case study will check out how Pex works on a method accepting a string type. Complex types ....?&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-8133743926608869564?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/8133743926608869564/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=8133743926608869564' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8133743926608869564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8133743926608869564'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/pex-test-case-3.html' title='Pex - Test case 3'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_GROsRPS-U-k/SInJoV-im-I/AAAAAAAAAMk/SoLkpBazhnk/s72-c/pexresults.JPG' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-8921312070442989864</id><published>2008-07-24T16:46:00.022+02:00</published><updated>2008-08-21T08:58:19.569+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - test case 2</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I'm currently trying out Pex , an automated unit test generator. I'm trying out several scenarios. If you like you can read about a &lt;a href="http://appdevchronicles.blogspot.com/2008/07/pex-test-case-1.html"&gt;previous test case &lt;/a&gt; I tried out. In the same spirit , I'll start of with what you could do without Pex.&lt;br /&gt;&lt;br /&gt;The code snippet is as follows. There is a "measurement class" that implements the following method (property).&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;pre class="c#" name="code" rows="10" cols="60" &gt;&lt;br /&gt;     private int mTemperature;&lt;br /&gt;&lt;br /&gt;        public int Temperature&lt;br /&gt;        {&lt;br /&gt;            get { return mTemperature; }&lt;br /&gt;            set { &lt;br /&gt;                if (value &gt; -274 &amp; value &lt; 1000)&lt;br /&gt;                {&lt;br /&gt;                     mTemperature = value; &lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    throw new System.ArgumentOutOfRangeException("Please .....");    &lt;br /&gt;                }&lt;br /&gt;               &lt;br /&gt;                }&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There are two test situations (different behaviours) in this unit to be tested.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;an integer value is assigned to a field&lt;/li&gt;&lt;br /&gt;&lt;li&gt;an exception is thrown&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If you would use the &lt;a href="http://appdevchronicles.blogspot.com/2007/10/test-specification-techniques.html"&gt;Equivalence class technique&lt;/a&gt; to establish a good test suite, you could come up with following findings.&lt;br /&gt;Valid classes&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;integer value&lt;/li&gt;&lt;br /&gt;&lt;li&gt;integer value between -274 and 1000&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Invalid classes&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;NOT an integer value&lt;/li&gt;&lt;br /&gt;&lt;li&gt;integer value smaller or equal than -274 &lt;/li&gt;&lt;br /&gt;&lt;li&gt;integer value bigger or equal than 1000&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Because the .NET type system gives us a hand (int) , our method only can accept integers. So we only have 1 valid class and two invalid classes or one if you would combine then in one sentence (Not between -274 and 1000). Both approaches should cover our two test situations (assignation and exception).&lt;br /&gt;&lt;br /&gt;Now we have to come up with actual values for these classes which shouldn't be too difficult. This would result in two physical test cases (i.e. unit tests). We could pick -30 and 1500 . Or -650 and 0. And so one... All these values should give equal test results while assuring complete coverage.&lt;br /&gt;&lt;br /&gt;In case of two invalid classes you will have three test cases :&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;valid : 25&lt;/li&gt;&lt;br /&gt;&lt;li&gt;invalid 1 : - 300&lt;/li&gt;&lt;br /&gt;&lt;li&gt;invalid 2 : 1250&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;A common place for errors are the comparison signs. The Border Value Analysis "technique" stipulates you should pick values around the "borders". In our example these are -274 and 1000. In addition you could also pick values aboove (and/or under) these border values. Any mistake (current or future) should be detected by our set of test cases (i.e. unit tests).&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;valid 1: 273&lt;/li&gt;&lt;br /&gt;&lt;li&gt;valid 2: 999&lt;/li&gt;&lt;br /&gt;&lt;li&gt;invalid 1 : - 274&lt;/li&gt;&lt;br /&gt;&lt;li&gt;invalid 2 : 1000&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;So which unit tests will Pex generate for us?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code" cols="60" rows="10"&gt;&lt;br /&gt;         [PexMethod()]&lt;br /&gt;        public void TemperatureTest(int aTemperature)&lt;br /&gt;        {&lt;br /&gt;            measurement target = new measurement();&lt;br /&gt;            int actual;&lt;br /&gt;            target.Temperature = aTemperature;&lt;br /&gt;            actual = target.Temperature;&lt;br /&gt;            PexValue.AddForValidation("actual",actual);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_GROsRPS-U-k/SIluPEG_mzI/AAAAAAAAAMM/q5G6j9ohapo/s1600-h/AllowException.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5226830047620340530" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SIluPEG_mzI/AAAAAAAAAMM/q5G6j9ohapo/s400/AllowException.JPG" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Pex, using the specified PexMethod, explored our code. It took him two runs to come up with the necessary values for temperature. On the last value (int.MinValue : the smalles possible 32-bit integer value in .NET ) it discovered an exception. Just like in "traditional" unit testing you can specify an "expected exception" . meaning when this exception is thrown, the test is succesfull because that is what you ....expected.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_GROsRPS-U-k/SIlxKHjrF_I/AAAAAAAAAMU/Ja6fwGCStho/s1600-h/AdjustPex.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5226833261181474802" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SIlxKHjrF_I/AAAAAAAAAMU/Ja6fwGCStho/s400/AdjustPex.JPG" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you re-run the PexMethod again you will see two classic unit test.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code" cols="60" rows="10"&gt;&lt;br /&gt;   public partial class measurementTest&lt;br /&gt;    {&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void TemperatureTestInt32_20080725_080720_000()&lt;br /&gt;        {&lt;br /&gt;            PexValue.Generated.Clear();&lt;br /&gt;            this.TemperatureTest(0);&lt;br /&gt;            PexValue.Generated.Validate("actual", "0");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [ExpectedException(typeof(ArgumentOutOfRangeException))]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void TemperatureTestInt32_20080725_082344_001()&lt;br /&gt;        {&lt;br /&gt;            this.TemperatureTest(int.MinValue);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you run these two unit tests and enable Code Coverage for the target assembly in VS Test framework, you will notice full coverage as understood by VS test framework.&lt;br /&gt;&lt;br /&gt;If you compare the Pex analysis with our "manual" analysis you can see that Pex took the minimal set of test cases to achieve full coverage (as understood by Visual Studio). For example someone would change the comparision operator in the method, the unit tests generated by Pex will not detect it in this particular example.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But if you would slightly change the pexMethod (tip from Peli de Halleux) you would see one extra unit test. You need to re-write the assert to verify the border values.&lt;br /&gt;&lt;pre class="c#" name="code" cols="60" rows="10"&gt;&lt;br /&gt;      [PexMethod()]&lt;br /&gt;        public void TemperatureTest(int aTemperature)&lt;br /&gt;        {&lt;br /&gt;            measurement target = new measurement(); &lt;br /&gt;            int actual;&lt;br /&gt;            target.Temperature = aTemperature;&lt;br /&gt;            actual = target.Temperature;&lt;br /&gt;            PexAssert.IsTrue((actual &gt; -274 &amp; actual &lt; 1000));&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_GROsRPS-U-k/SImaaTcVdnI/AAAAAAAAAMc/Tbtmp2FvCvQ/s1600-h/PexBorder.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_GROsRPS-U-k/SImaaTcVdnI/AAAAAAAAAMc/Tbtmp2FvCvQ/s400/PexBorder.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5226878619226568306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The unit tests generated by Pex would now include the 1000 border value. I don't understand yet why -274 wasn't picked up. I guess it has to do with the fact 0 was the value chosen in the first run. Maybe there are better ways to write this PexMethod? I'll will need to look into the "assumptions" part of Pex (PexAssume class). &lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code" cols="60" rows="10"&gt;&lt;br /&gt;    public partial class measurementTest&lt;br /&gt;    {&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void TemperatureTestInt32_20080725_111609_000()&lt;br /&gt;        {&lt;br /&gt;            this.TemperatureTest(0);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [ExpectedException(typeof(ArgumentOutOfRangeException))]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void TemperatureTestInt32_20080725_111609_001()&lt;br /&gt;        {&lt;br /&gt;            this.TemperatureTest(int.MinValue);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        [ExpectedException(typeof(PexAssertionViolationException))]&lt;br /&gt;        [PexGeneratedBy(typeof(measurementTest))]&lt;br /&gt;        public void TemperatureTestInt32_20080725_111953_002()&lt;br /&gt;        {&lt;br /&gt;            this.TemperatureTest(1000);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Is it worthwile to look for test cases but beyond absolute minimal? Well, it dependends. One of the advantages of of having (automated) unit tests is the ability to use them over and over again. In the context of regression testing these test suitses can be of great help to assure that all code that is using your unit (i.e. method) will still function after you made modifications. or least you will know in which situation something will break so you can take appropriate measures (defaults, overloads, release notes ,...).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code" cols="60" rows="10"&gt;&lt;br /&gt;         private int mTemperature;&lt;br /&gt;&lt;br /&gt;        public int Temperature&lt;br /&gt;        {&lt;br /&gt;            get { return mTemperature; }&lt;br /&gt;            set { &lt;br /&gt;                if (value &gt; -274 &amp; value &lt;= 1000)&lt;br /&gt;                {&lt;br /&gt;                     mTemperature = value; &lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    throw new System.ArgumentOutOfRangeException("Please ...");    &lt;br /&gt;                }&lt;br /&gt;               &lt;br /&gt;                }&lt;br /&gt;        }                             &lt;br /&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So if regression testing is of high priority , it think some methods need those extra test cases. They can happily live beside the ones generated by Pex. It is sometimes (value of software; money, safety) better to have "too much"  than "too little" test cases I think (even if it means extra (test) code to maintain.&lt;br /&gt;&lt;br /&gt;As shown in the example, the way you setup your Pexmethod will influence how Pex "explores" your code. Although the the call to the (setter) method was the same. The Assertion part of the Pexmethod made Pex do an extra effort.&lt;br /&gt;&lt;br /&gt;If you have other thoughts or remarks about pex or devloper testing in general, don't hesitate to drop a comment.&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alexander&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-8921312070442989864?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/8921312070442989864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=8921312070442989864' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8921312070442989864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8921312070442989864'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/pex-test-case-2.html' title='Pex - test case 2'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_GROsRPS-U-k/SIluPEG_mzI/AAAAAAAAAMM/q5G6j9ohapo/s72-c/AllowException.JPG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3801507252680879162</id><published>2008-07-23T14:21:00.028+02:00</published><updated>2008-08-21T08:58:32.633+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Pex - test case 1</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I just &lt;a href="http://appdevchronicles.blogspot.com/2008/07/starting-with-pex-program-exploration.html"&gt;started &lt;/a&gt;investigating Pex . In order to learn the tool I'm using several (academic) test cases to see how Pex can help there.&lt;br /&gt;&lt;br /&gt;This case case is called Commercial Cut percentage for an order. In our Order system we have implemented a rule that will calculate the commercial cut based on the total OrderAmount. The following table depicts the rules for applying the commercial cut.&lt;br/&gt;&lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Total (rounded) order-amount (€)&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;=1500&lt;/td&gt;&lt;br /&gt;&lt;td&gt;[1501-5000]&lt;/td&gt;&lt;br /&gt;&lt;td&gt;[5001-10000]&lt;/td&gt;&lt;br /&gt;&lt;td&gt;[10001-25000]&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&gt;25000&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Commercial cut&lt;/td&gt;&lt;br /&gt;&lt;td&gt;0&lt;/td&gt;&lt;br /&gt;&lt;td&gt;2&lt;/td&gt;&lt;br /&gt;&lt;td&gt;3&lt;/td&gt;&lt;br /&gt;&lt;td&gt;4&lt;/td&gt;&lt;br /&gt;&lt;td&gt;5&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have implemented this rule in a c# method. For the sake of this exercise I will not argue about whether or not this should be a private method (Which by the way can perfectly be unit tested in the VS Test framework).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;pre class="c#" cols="100" rows="10" name="code"&gt;&lt;br /&gt;       public uint DetermineCommercialCut(uint aTotalOrderAmount)&lt;br /&gt;       {&lt;br /&gt;&lt;br /&gt;           if (aTotalOrderAmount &lt;= 1500)&lt;br /&gt;           {&lt;br /&gt;               return 0;&lt;br /&gt;           }&lt;br /&gt;           else if (aTotalOrderAmount &gt; 1500 &amp; aTotalOrderAmount &lt;= 5000)&lt;br /&gt;           {&lt;br /&gt;               return 2;&lt;br /&gt;           }&lt;br /&gt;           else if (aTotalOrderAmount &gt; 5000 &amp; aTotalOrderAmount &lt;= 10000)&lt;br /&gt;           {&lt;br /&gt;               return 3;&lt;br /&gt;           }&lt;br /&gt;           else if (aTotalOrderAmount &gt; 10000 &amp; aTotalOrderAmount &lt;= 25000)&lt;br /&gt;           {&lt;br /&gt;               return 4;&lt;br /&gt;           }&lt;br /&gt;           else&lt;br /&gt;           {&lt;br /&gt;               return 5;&lt;br /&gt;           }&lt;br /&gt;       }&lt;br /&gt;   &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Of course we will unit test this class method. This method should always return some positive integer value back depending on total order amount that is supplied via unsigned integer parameter. So I give a positive integer (or zero) to the method and I receive a positive integer (or zero) back. Of course the purpose of the method is determine the commercial cut percentage based on the order amount. Our table showed on the rules we need to apply and our code is (hopefully) constructed in the same way. So we will construct a unit test that will call this method. &lt;pre class="c#" cols="60" rows="10" name="code"&gt;&lt;br /&gt;   [TestMethod()]&lt;br /&gt;   public void DetermineCommercialCut_ZeroOrderAmount()&lt;br /&gt;      {&lt;br /&gt;            Order target = new Order();&lt;br /&gt;            uint aTotalOrderAmount =0;&lt;br /&gt;            uint expected = 0;&lt;br /&gt;            uint actual;&lt;br /&gt;            actual = target.DetermineCommercialCut(aTotalOrderAmount);&lt;br /&gt;            Assert.IsTrue(expected == actual);&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We could continue with testing all positive integers up to 4.294.967.295. Of course this is not worthwhile. We can pick certain values for this entire collection in such way that any value within certain ranges of this big collection , will (should) behave in the same way. This is referred to as &lt;strong&gt;equivalence classes &lt;/strong&gt;in testing literature. So whether I pick 0 or 1500 as total (rounded) order amount or any value in between, it should always resolve to a return value of zero. So based on this principle I can detect several equivalence classes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Must be positive integer&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integers between 0 and 1500 included&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integers between 1501 and 5000 included&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integers between 5001 and 10000 included&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integers between 10001 and 25000 included&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integers higher then 25000&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I’m spotting 5 valid classes. Because the.NET type system helps me out here I don’t need explicit checks on the invalid class namely negative integers.&lt;br /&gt;&lt;br /&gt;now I need to pick a value I will actually use in my unit tests. I will at least need to pick 5 values, one from each equivalence class. In my test I will verify if the reduction cut is appropriate for that value.&lt;br /&gt;So instead of making 4.294.967.295 unit tests I only need 5 to “cover” all possible test situation ( different commercial cut percentages).&lt;br /&gt;&lt;br /&gt;Another technique that is usually combined with the former is &lt;strong&gt;border value analysis&lt;/strong&gt;. In the example I can with a minimal additional effort also verify if the comparison signs are as they were intended to be. Instead of picking any value in the equivalence class , I will look up the values that are used in the conditions for example. Instead of 2531 , I will pick 5000 just at the border. So 5000 should give me a commercial cut of 2. Just like 2531 but I have an extra check on the comparison sign with no extra effort. With a little more effort I could also include the values just under (or above) the border.&lt;br /&gt;&lt;br /&gt;So basic techniques told me I need 5 test case to fully test my rule (i.e. Method). So this means 5 Visual Studio test methods. Actually , Visual Studio test Framework can, in this case , help us even further with reducing the number of unit test to …..one. That is one &lt;strong&gt;data-driven unit test&lt;/strong&gt;. What we do, is externalize the test data values into for example an Excel file. This data-source will then “feed” our data-driven unit test with actual values. So although we have only one written unit test, we would like this test code to be executed 5 times. We now use this table (with some modification) as data-source for our data-driven unit test in Visual Studio 2008. For more info see &lt;a href="http://msdn.microsoft.com/en-us/library/ms182519.aspx"&gt;MSDN&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" cols="60" rows="10" name="code"&gt;&lt;br /&gt;        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",&lt;br /&gt;                     "DataDirectory\\testData.xml",&lt;br /&gt;                     "CommercialCut", DataAccessMethod.Sequential),&lt;br /&gt;        DeploymentItem("TestProject1\\testData.xml")]&lt;br /&gt;        [TestMethod()]&lt;br /&gt;        public void DetermineCommercialCut_DataDriven()&lt;br /&gt;        {&lt;br /&gt;            Order target = new Order();&lt;br /&gt;            uint aTotalOrderAmount = System.Convert.ToUInt32(this.TestContext.DataRow["input"]);&lt;br /&gt;            uint expected = System.Convert.ToUInt32(this.TestContext.DataRow["expected"]);&lt;br /&gt;            uint actual;&lt;br /&gt;            actual = target.DetermineCommercialCut(aTotalOrderAmount);&lt;br /&gt;            Assert.IsTrue(expected== actual);&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We determined on basis of our analysis that 5 test-cases should cover the testing of the rule. Here Visual Studio Test framework also can help us by instrumenting the code before executing the unit tests (&lt;strong&gt;Code coverage&lt;/strong&gt;). A nice feature of the Visual Studio Test framework is the colorization of the code under test to show which parts have been “touched” by the unit tests and which parts didn’t.&lt;br /&gt;&lt;br /&gt;When looking at the Visual Studio Code coverage results of one test executed :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5226189944230725986" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/SIcoEJKXSWI/AAAAAAAAALk/YYVrqULzXkE/s400/CodeCoverageSingleTest.JPG" border="0" /&gt;&lt;br /&gt;You can see the statements in different coloring; touched versus not touched. This should tell you that you must add some test cases to see code paths in your method also work as you intended and consequently coded.&lt;br /&gt;&lt;br /&gt;If you would run the data-driven test with the 5 test cases you would get the following result :&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5226191060209792370" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/SIcpFGggdXI/AAAAAAAAALs/BI6L9-6ByTg/s400/codeCoverageAlltests.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Everything is highlighted in blue, meaning that every “block” in our code has been executed during the run of our unit test. That should come as no surprise because we rigorously followed our table for our rule.&lt;br /&gt;&lt;br /&gt;So far our “manual” effort . Lets see how Pex can help you. So the documentation states that Pex can create a test suite with a high coverage by exploring your code triggered from a &lt;strong&gt;parameterized test &lt;/strong&gt;you will have to write.&lt;br /&gt;&lt;br /&gt;I highly recommend reading the &lt;a href="http://research.microsoft.com/pex/articles/pextutorial.pdf"&gt;tutorial &lt;/a&gt;for more background information on Pex. Meanwhile I will continue with the example to show you how Pex can create a test suite for us.&lt;br /&gt;&lt;br /&gt;First we must create a “parameterized” unit test to give Pex an entry point into our code under test. “Parameterized Unit Tests (PUTs) are... tests that take parameters. Unlike traditional unit tests, which are usually closed methods, PUTs take any set of parameters. Is it that simple? Yes! From there, Pex will try to generate the (minimal) set of inputs that fully coverthe code reachable from the test. “&lt;br /&gt;&lt;br /&gt;So in our case this could look something like:&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" cols="60" rows="10" name="code"&gt;&lt;br /&gt;[PexMethod()]&lt;br /&gt;public void CaluclateReductionPercentageTest(uint aSales)&lt;br /&gt;{&lt;br /&gt; Order target = new Order();&lt;br /&gt; uint actual;&lt;br /&gt; actual = target.DetermineCommercialCut(aSales);&lt;br /&gt; PexValue.AddForValidation("result", actual);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can launch Pex from within Visual Studio 2008 C# by right clicking the mouse&lt;br /&gt;(or pressing CTRL+F8). You will see a menu option ” &lt;strong&gt;Run Pex Exploration&lt;/strong&gt;”.&lt;br /&gt;This will launch Pex in doing it’s job, running your code (several times) while generating the&lt;br /&gt;right combination of input values for each possible code path and then generating the code&lt;br /&gt;for all the test cases.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5226192551130075778" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SIcqb4nmkoI/AAAAAAAAAL0/ewj-XRnne1U/s400/PexgeneratedUnittests.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pex &lt;strong&gt;generated &lt;/strong&gt;5 tests for us. It clearly also detected (in another way) that there are 5 test cases needed to cover the code. If we take our 5 equivalence classes we can see that this is correct. If our “conduct-of-test” specifies the use of border-value analysis where appropriate , then these values are not so well chosen in my opinion.&lt;br /&gt;&lt;br /&gt;Lets say that we want to add an extra level of commercial cut for sales between 1000 and 1500 Euros. And we want to let our client enjoy a commercial cut of 1 percent.&lt;br /&gt;&lt;br /&gt;In the manual test analysis we would come up with an additional equivalence class. Pex can also detect this.&lt;br /&gt;&lt;br /&gt;But first lets re-run our initial set of unit tests generated by pex.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img id="BLOGGER_PHOTO_ID_5226193770281268034" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/SIcri2T5c0I/AAAAAAAAAL8/n_9lMRQW-cM/s400/RerunTests.JPG" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Our Code Coverage run should warn us that we missed out on some parts of the code. We need another unit test. To do so , we will re-run Pex on our pexMethod. The will force pex to examine our code again and it should find an extra path in our code.&lt;/p&gt;&lt;img id="BLOGGER_PHOTO_ID_5226196194199470722" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/SIctv8HCAoI/AAAAAAAAAME/6xsiKV62aTM/s400/rerunpex.JPG" border="0" /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Doing so resulted in pex finding an additional test (nr 3 - see screenshot). If we run the generated test methods and also look at the coverage findings we find a positive result.&lt;/p&gt;&lt;br /&gt;So in a nutshell. In this (although academic) situation, Pex found the same test cases if we would use a manual technique. Border value Analysis would be advantageous in this test case but Pex doesn't propose these values while exploring this method based on the PexMethod we proposed.&lt;br /&gt;&lt;br/&gt; So the most important lesson I think is , as also stated in the Pex &lt;a href="http://research.microsoft.com/pex/wiki/book.html#Frequently_Asked_Questions"&gt;FAQ &lt;/a&gt;: Use Pex as one of your tools not as the (only) tool.&lt;br /&gt;&lt;p&gt;Maybe you also have tried out Pex? Don't hesitate to share....&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Thanks for reading.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;ps: I'm still experimenting with SyntaxHighLighter. If you have any tips how to improve showing code snippets in Blogger...let me know.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3801507252680879162?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3801507252680879162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3801507252680879162' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3801507252680879162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3801507252680879162'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/pex-test-case-1.html' title='Pex - test case 1'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/SIcoEJKXSWI/AAAAAAAAALk/YYVrqULzXkE/s72-c/CodeCoverageSingleTest.JPG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3672700951556514197</id><published>2008-07-22T15:06:00.004+02:00</published><updated>2008-08-21T08:58:44.316+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Pex'/><title type='text'>Starting with Pex (Program Exploration)</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I recently downloaded Pex from &lt;a href="http://research.microsoft.com/pex/"&gt;Microsoft Research&lt;/a&gt;.  Pex is a tool for finding test  cases for you on basis of “looking” and “executing” your code.  It is fully integrated in Visual Studio 2008 (c#).  Pex explores your code by executing special Pex test method you have written. It basically comes down by making a “parameterized” version of a unit test you would normally make. This Pex test method will then call you unit under test (i.e. class method). Pex supplies values for the parameterized unit test . Meanwhile it will instruments your code do see which conditions it needs to check and which code paths it took during the exploration phase. After completing it adventure, it will generated unit test code. This unit test can then be executed by the Visual Studio Test Framework. For more &lt;a href="http://research.microsoft.com/pex/documentation.aspx"&gt;information.....&lt;/a&gt;  Before taking Pex for a spin , let's look at why a Pex was created.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Automated Unit testing is considered a good practice in software development. Nevertheless it is usually perceived as a burden by the developer.  Besides the writing the actual code the programmer has to create and maintain this extra test code and of course exercising these unit tests.  Depending on the code the amount of test cases , hence the unit test, can quickly grow. Also if you exercise the practice of “good” code coverage by your unit tests, you’ll discover that writing unit tests is hard work. &lt;br /&gt;&lt;br /&gt;Sometimes the amount of test code supersedes the code under test. Much effort goes into creating the right amount of test cases so they cover every “corner” of you code. This code coverage criterion should result in a higher probability to find errors in your code. There several techniques that can help you establish these test cases. But these still leave writing the unit tests yourself.&lt;br /&gt;&lt;br /&gt;Here's where pex steps in. Pex from Microsoft research can help achieve this coverage criterion by  dynamically introspecting your code and based on that analysis can generate different test cases in the form “traditional” unit tests for the Visual Studio test framework.&lt;br /&gt;&lt;br /&gt;I currently trying out some scenario's.  Keep an eye for future posting...&lt;br /&gt;&lt;br /&gt;Thanks for reading.&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3672700951556514197?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3672700951556514197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3672700951556514197' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3672700951556514197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3672700951556514197'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/starting-with-pex-program-exploration.html' title='Starting with Pex (Program Exploration)'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-334833277843438769</id><published>2008-07-17T09:16:00.005+02:00</published><updated>2008-07-17T11:21:15.544+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><title type='text'>Design for Testability - Dependencies</title><content type='html'>&lt;p&gt;Hello,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This post is a continuation on previous posts about design-for-testability (&lt;a href="http://appdevchronicles.blogspot.com/2008/05/design-for-testability.html"&gt;here &lt;/a&gt;and &lt;a href="http://appdevchronicles.blogspot.com/2008/07/design-for-testability-developer.html"&gt;here&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Control and observation are important characteristics in test-automation. If our code under test makes an effort to facilitate this , we improve the testability of our code. Improving the testability should lead to find any errors in our code more easily. The more we errors we find early in the development cycle, the cheaper it is to correct them. We early testing and defect correction, we get a good feel on the quality of the software. We can make educated decisions on when to promote the code to QA and/or production. When our customer can use our software to do their job , they create value for the company they work for ….(I will stop rambling here) . But you see , testability (and in a broader sense quality assurance) should be baked into the software. The entire organization can benefit from it.&lt;br /&gt;&lt;br /&gt;Let’s start on the “control” aspect of our code under test (CUT) and specifically on the controlling the dependencies of our CUT with other parts of the program or the environment it runs in.&lt;br /&gt;&lt;br /&gt;It is in the nature of an object-oriented language to build up a program from lot of different “units” where some “units” or better classes work closely together to make something happen. Object-oriented principles like single-responsibility, information-hiding , inheritance , etc are common in this world. So it is quite natural that classes have &lt;strong&gt;dependencies&lt;/strong&gt; on other &lt;strong&gt;classes&lt;/strong&gt;. The term coupling is often used to state the existence of relationships between class (inheritance, composition , etc). coupling is evitable. If there were no coupling we would end up with monolithically part of codes, actually they would be separate programs. The large classes would be too complex and the cohesion of the operations and member data would very low.&lt;br /&gt;&lt;br /&gt;In the realm of testability we sometimes want to be able to test a class in a controlled way, maybe even in total isolation. In order to do that we must be able to control the dependencies. The fewer the dependencies the easier it will be. Hence “managed” coupling can increase testability.&lt;br /&gt;&lt;br /&gt;Programs run on machines and make also use of their &lt;strong&gt;environment&lt;/strong&gt;. For example the file system, Message Queue system, database systems , web services, etc. These resource dependencies are expressed in the programs usually via string tokens. For example a folder name, database connection string, queue name, web service URL etc. A good practice of course is to externalize the values for these resources for example in a configuration file. These practice is also beneficial for testability. Avoiding “hard-coded” resource strings in your code is of course not a good programming practice. Because many times the resource string are depended on where the program actually will run. For example development , production or …testing. So controlling the resource tokens outside the program can give us flexibility will setting up tests.&lt;br /&gt;.NET has excellent support to easily consume these externalized resource identifiers in your programs. In the Visual Studio test framework you can easily let the test framework pick up these configuration files and let your code under test use the configured element just like if the code under test was running in their proper host (windows app, web service, etc). In other words , you will copy the configuration info that you need for the code under test from the base app.config or web.config in your test project and modify it as needed.&lt;br /&gt;&lt;br /&gt;Let’s focus again on &lt;strong&gt;class dependencies&lt;/strong&gt;. So dependencies are inevitable but we can make them more manageable for testing purposes ( or other reasons). In order to continue our discussion lets introduce some terms. If a class A depends on another class B to fulfil its functionality A is called a client class and B is called a server class. During unit test we want to test a class in isolation. Therefore we want to substitute its server classes by stubs or mock objects . Hard-wired dependencies to server classes hinder this. A dependency on a server class is hard-wired if the server class can not be substituted by some other class (e.g. a subclass of the server class) without changing the source code of the client class. Similar problems arise during integration testing if a server class should be stubbed because it is not test-ready. So how can we manage class dependencies that will benefit testability.&lt;br /&gt;One of the areas lies in the construction of the dependencies. We don’t control them. So our solution strategy should revolve around getting control about the creation of the dependencies. Several &lt;strong&gt;techniques&lt;/strong&gt; can help us to come up with a solution:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Interface-based programming : Separating the interface from the implementation is core principle. Our client class uses an abstraction of a server class (interface) , not a particular implementation of it (object). So during testing we could create another implementation of the server class that implements the correct interface. This “test-double” (Gerard Meszaros , xUnit patterns) version of our server class can for example always give a fixed set of values back or just ignores the fact that we ask it to do something. Interfaces are first-class citizen in .NET so you should have no problems with this. But this technique is just a first step toward the solution. We still need to hook up an implementation of the server class into the client class at test time. &lt;/li&gt;&lt;li&gt;Service locator: We would delegate the creation of objects to a specialized object that for example would fabricate objects based on a string identifier.&lt;/li&gt;&lt;li&gt;Provider model : Variation of Interface-based programming :. Abstract class , concrete implementation hooked up at runtime (configuration file). You can a test-specific implementation of the provider in order to control the tests &lt;/li&gt;&lt;li&gt;Manual Dependency injection : We will make another class responsible to establish the link between the client and the server. We will add a parameter of the server type to a method of the client class (a constructor, or a method that requires access to a server instance, or a dedicated setup method) which allows other objects to set the link. During testing the parameter(s) can be used to establish a link to a “test-double” instead.&lt;/li&gt;&lt;li&gt;Automatic dependency injection : a DI container framework takes care of the details of which objects are interconnected, so you can build each one independently. No need for passing the dependencies along with the constructor or methods or assigning properties with dependent objects &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Still there some &lt;strong&gt;concerns&lt;/strong&gt; (or trade-offs) you should take into account;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Information hiding :Why can’t leave it up to A to know its dependencies : Exposing the dependencies in a constructor function can be viewed a violation of encapsulation because now a client of Class A would have to create instances of Class B first before calling the constructor function of class A&lt;/li&gt;&lt;li&gt;The ability to substitute a server class is not always important for the “production” implementation. So is testability a good enough reason for implementing this possibility?&lt;br /&gt;We could make a special constructor that will accept the dependencies. The default constructor would use that hard-wired implementations.&lt;br /&gt;If there are dependencies on many server classes, this approach would result in too many parameters. &lt;/li&gt;&lt;li&gt;DI Framework to the rescue ...but Someone has to know the dependencies&lt;br /&gt;Assembler , DI Framework via declarations or via config files&lt;br /&gt;&lt;a title="" style="mso-footnote-id: ftn1" href="http://www.blogger.com/post-edit.g?blogID=6998972826668184815&amp;amp;postID=334833277843438769#_ftnref1" name="_ftn1"&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;There are still other things besides managed coupling you can work on to improve testability , hence the quality of our software : cohesion, encapsulation, ... But that's for another post.&lt;/p&gt;&lt;p&gt;Maybe you have others techiques to improve testability? If you would like to share them, don't hesitate to drop a commont.&lt;/p&gt;&lt;p&gt;Thanks in advance.&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-334833277843438769?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/334833277843438769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=334833277843438769' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/334833277843438769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/334833277843438769'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/design-for-testability-dependencies.html' title='Design for Testability - Dependencies'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3895366082903278233</id><published>2008-07-15T14:19:00.017+02:00</published><updated>2008-09-10T08:20:44.407+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Winforms'/><title type='text'>Winforms (VS2005) DataGridViewComboBoxColumn,  CTRL+0 and Cannot set Column 'myColumnName' to be null. Please use DBNull instead.</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;I recently had some trouble with setting a &lt;strong&gt;dataGridViewComboboxColumn&lt;/strong&gt; to a dbNull value with the &lt;strong&gt;CTRL+0&lt;/strong&gt; (zero) keystroke. As you may know, the datagrid supports the CTRL+0 keycode to force a dbNull value into cell and subsequentialy into the bound datasource (a datatable in my case). In other words you can use that to clear out a combo box's value and set it back to "nothing". At least when the bound datatable column allows DbNull to be true. &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;This is where I experienced some strange behaviour. I used a datagridView to display some customer data. One of the fields specifies an optional characteristic , namely the qualification of a customer. At database level this is enforced with a referential integrity constraint in the form of foreign key specification with a look-up table. The primary key of this look-up table is an integer. Of course in the datagrid , on the comboxbox showing the customer qualification , you will see a description (cfr. valuemember versus DisplayMember).&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;This is where it goes wrong. When I try to clear an existing value in the combobox , I get the following error message. &lt;strong&gt;Cannot set Column '&lt;columnname&gt;' to be null. Please use DBNull instead&lt;/strong&gt;.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;What is even more strange is that when you have a combobox in the datagridview where the valueMember's type is System.String, You will not have this exception. It just works. It is also only apparent with a datagridViewComboxBoxColumn. Because if I would use a&lt;br /&gt;DataGridViewTextBoxColumn for the "integer" case, I would neither experince any problem with CTRL+0.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;I looked for a solution on Google and I stumbled on this &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=220958&amp;amp;SiteID=1"&gt;post &lt;/a&gt;. Somewhere on the middle you will see an entry by &lt;strong&gt;Mark Rideout&lt;/strong&gt; , DataGridView Program Manager Microsoft (27 Jan 2006, 3:34 PM ) . ...And he talks about a bug. But more interssenting for me he also hints a possible work-around.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;He talks about &lt;strong&gt;overriding&lt;/strong&gt; the &lt;strong&gt;DataGridView.ProcessDataGridViewKey&lt;/strong&gt; Method . This method calls the key-processing method appropriate to the key pressed. In this method you could check for the CTRL+0 keystroke (D0) . That is exactly what I immediately tried out. I made a custom DataGridView (i.e. I created a class inheriting from the System.Windows.Forms.DataGridView and overrided the ProcessDataGridViewKey(see &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.processdatagridviewkey.aspx"&gt;MSDN&lt;/a&gt;) . In this method I check for the CTRL+0 keystroke and some other characteristics . And if everything is true, I programmatically set the value for the currentcell to system.DbNull.Value. &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5223993853432358178" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/SH9au1ao5SI/AAAAAAAAALc/pVK3CdTWCp8/s400/CustomDataGridView.jpg" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="vb.net" rows="10" cols="40" name="code"&gt;&lt;br /&gt;Public Class CustomDataGridView : Inherits System.Windows.Forms.DataGridView&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    Protected Overrides Function ProcessDataGridViewKey(ByVal e As System.Windows.Forms.KeyEventArgs) As Boolean&lt;br /&gt;&lt;br /&gt;        If (e.KeyCode = Keys.D0 or  e.KeyCode = keys.NumPad0) _&lt;br /&gt;            AndAlso TypeOf MyBase.Columns(MyBase.CurrentCell.ColumnIndex) Is _&lt;br /&gt;              System.Windows.Forms.DataGridViewComboBoxColumn _&lt;br /&gt;            AndAlso MyBase.Columns(MyBase.CurrentCell.ColumnIndex).ValueType IsNot _&lt;br /&gt;              GetType(System.String) Then&lt;br /&gt;            MyBase.CurrentCell.Value = System.DBNull.Value&lt;br /&gt;            Return True&lt;br /&gt;        Else&lt;br /&gt;            Return MyBase.ProcessDataGridViewKey(e)&lt;br /&gt;        End If&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    End Function&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;And guess what? It works (at least for me)! I also tried it in VS2008. There the same error is thrown ( I gues the bug report got lost somewhere ). But the same trick with ProcessDataGridViewKey works in VS2008.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;I haven't tried it yet on other dataTypes like guid's and so. That why i check for datatypes in the code. But for my situation, this solution is OK .&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Maybe there is another solution? If you know of one, don't hesitate to let me know...&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Meanwhile if you like, you can download my &lt;a href="http://www.4shared.com/file/55376536/9e7866c9/TestControlPlusZero.html"&gt;test-program&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Thanks for reading.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Best regards,&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Alexander&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3895366082903278233?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3895366082903278233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3895366082903278233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3895366082903278233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3895366082903278233'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/winforms-vs2005-datagridview-combobox.html' title='Winforms (VS2005) DataGridViewComboBoxColumn,  CTRL+0 and Cannot set Column &apos;myColumnName&apos; to be null. Please use DBNull instead.'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/SH9au1ao5SI/AAAAAAAAALc/pVK3CdTWCp8/s72-c/CustomDataGridView.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-4401923666582435431</id><published>2008-07-09T15:12:00.001+02:00</published><updated>2008-07-09T15:27:56.660+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET design'/><title type='text'>Design for testability - developer testing context</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;Some more thoughts on design for testatbility in the developer testing context (see previous &lt;a href="http://appdevchronicles.blogspot.com/2008/05/design-for-testability.html"&gt;post &lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Test automation plays an important role in the developer testing context. The advent of the xUnit testing concept , nUnit and the integration of xUnit concept in Visual Studio, has put developer testing more in focus.&lt;br /&gt;The test case is a description that tells us how we can see whether to system has done something as we expected it do that something.&lt;br /&gt;Before executing a test , we must put the put the system in state so our test can actually operate. For example before testing the deletion of an order in our order system, the system must contain an order that we know of. For example a order record in a database.&lt;br /&gt;The act of deleting an order necessitates that we can say to the system that we want to delete that explicit order . So not only to we need control of the initial situation, but we also need control of specifying the input and controlling the place where the order is physically kept (i.e. our test database with Order record with ID ORD1)&lt;br /&gt;After executing the functionality, we must be able to verify if the system has actually done its piece of work. We must “see” the result of its processing. We need to compare this outcome with our initial expectations. A discrepancy can mean either the behaviour of the system was not correct or test case was not correct in terms of initial situation , the actions we took or the expected results.&lt;br /&gt;&lt;br /&gt;An automated test (case) in xUnit terms can be viewed as follows (freely adapted on drawings found on &lt;a href="http://xunitpatterns.com/"&gt;http://xunitpatterns.com/&lt;/a&gt; (Gerard Meszaros)).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5221003142984342402" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/SHS6skzHm4I/AAAAAAAAAKs/J4LFGhf5ppI/s400/xUnittest.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Automated means that important steps in the execution of a test are preformed “automatically” . In other words exercising a test case on a unit (a method ) involves programmatically&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; supplying the initial situation (setup)&lt;/li&gt;&lt;li&gt;doing the actions (execute)&lt;/li&gt;&lt;li&gt;comparing the actual results with expected values (assert)&lt;/li&gt;&lt;li&gt;Cleaning up (teardown) so the next test case can proceed in a clean situation.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So how can we improve the testability in a developer context. On which aspects of the code  can we influence the ease of performing developer test and facilitate the localisation of defects.&lt;br /&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Control : In order make automation possible we need to be control of the initial situation as of the all the input that a method needs, so we can steer the processing of the unit in such a way it will produce the outcome we expect.&lt;/li&gt;&lt;li&gt;Observation : In order to compare actual and expected results , we must be able to observe what the outcome of the processing of a unit is. &lt;/li&gt;&lt;li&gt;Complexity: Network integration, database integration, Message queuing, Security , Registry, Windows services, COM+ , …. Makes it difficult to set up a test environment.&lt;br /&gt;Large methods with complex conditional flow necessitates many test case in order to get desired test coverage.&lt;br /&gt;Inheritance : abstract base class can not be instantiated.&lt;br /&gt;Large inheritance tree : may test cases to see if  combination of base and specialized code works as expected.&lt;/li&gt;&lt;li&gt;Isolation: Ability to isolate certain dependencies and replacing them with test-doubles improves testability because we control what the test-doubles will do.  That way we can concentrate on the logic in the CUT . The DUT will replaced by a test-double. Any calls from the CUT to the DUT (replaced by the test-double) will result in “controlled answers or behaviour”. Hence our test case for the CUT will be easier to setup&lt;/li&gt;&lt;li&gt;Separation of concerns : The class with a clear responsibility should improve testability in terms of knowing what to test in the first place.&lt;br /&gt;Smaller things to test&lt;/li&gt;&lt;li&gt;Heterogenity : Single language or language framework improves testability&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you have remarks or other thoughts, don't hesitate to drop a comment.&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-4401923666582435431?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/4401923666582435431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=4401923666582435431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/4401923666582435431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/4401923666582435431'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/07/design-for-testability-developer.html' title='Design for testability - developer testing context'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_GROsRPS-U-k/SHS6skzHm4I/AAAAAAAAAKs/J4LFGhf5ppI/s72-c/xUnittest.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3235191856994357104</id><published>2008-05-23T11:18:00.000+02:00</published><updated>2008-05-23T11:39:10.761+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET design'/><title type='text'>Design for Testability</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I have been reading up on "design for testability" because some of the code I deal with is not always easy to test.  Some thoughts ....&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Context&lt;/h2&gt;&lt;br /&gt;“Business” wants software application to help them do their job. They use them because they bring “value” to them. In order to make that happen software application must do what they are required to do (fit for purpose) and must be “reliable”.&lt;br /&gt;&lt;br /&gt;Through a mixture of process guidance, technology and human skills,  to use the previous to elements efficiently and effectively, IT tries to deliver those application on time while adhering to the intrinsic quality attributes like for example reliability. Quality processes are put in place to ensure achievement.  In order to assess the if the quality attributes are indeed incorporated into the software product, we need to check it. This is where testing comes in. Testing should give us insight into the quality of a system. This insight should help us decide to release the software for usage by the business because it can bring value to the business. Or it can tell us that there are still some discrepancies and we need to improve quality before handing it over to the business.&lt;br /&gt;&lt;br /&gt;Testing is some something we must do although it does not immediately raises the quality of the system. It reports only. Many times “business” can not understand why we can’t deliver something right the first time. Testing costs money!  Software creation is still an error-prone endeavour for many reasons despite all advancement in processes , technology and skills of people.  In other words we start off with the assumption (certainty!) that software contains errors. Both functional and programming wise. Testing is about finding those. So it is important that we make the best possible test cases to reveal them. Use tooling to support our testing effort etc.  Bust beside the test process it self , we can do more.&lt;br /&gt;&lt;br /&gt;During the inception and construction of software we can introduce measures to make this testing effort even more efficient and effective. In other words we must make our system as “testable” as possible in order to and to facilitate performing the test and finding the errors.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Testability&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Testability is about the ease of performing test against your system and ability of the tests to reveal any defects in a certain context. The context of the test , system testing (functional and non-functional) or developer testing, puts different meanings to testability. Also is it important that other software artefacts beside code,  affect testability ; for example the requirement specification documents.&lt;br /&gt;&lt;br /&gt;These are some aspects that influence the testability :&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Understanding:  The better you know what the thing is supposed to do , the better you can test for it. &lt;/li&gt;&lt;li&gt;Controlling ; You must be able to manipulate the input , in order to verify the correctness of the output.&lt;/li&gt;&lt;li&gt;Operational : We can only test it when it works !&lt;/li&gt;&lt;li&gt;Visibility : You can only verify the result , if you can see the output.&lt;/li&gt;&lt;li&gt;Simplicity : The less there is to test , the more quickly we can test it&lt;/li&gt;&lt;li&gt;Stability : The fewer the changes to less test if need to re-do and/or re-write&lt;br /&gt; &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So manipulating the influencers, can change the testatbility !&lt;/p&gt;&lt;p&gt;It is important to acknowledge that testability does not come on its own. We must take testing into account from the beginning of our software development endeavour. Because we know our software will contain errors (this will only increase with the size and complexity of today’s systems), we must prepare for it to easily test our system and find them before we ship the code.  &lt;/p&gt;&lt;p&gt;In other words we must design for testability. It is important because testing costs money. Also faulty software systems can cost the business money (in the best case or worse in case of threat to safety or life) . Therefore  we must make the testing as effective and efficient as possible. But Business  will benefit from this as well in the long run because we should be able to find defects thus raise the quality of the system, thus raise the value to the business. &lt;/p&gt;&lt;p&gt;Also future changes to the software to incorporate new requirements will benefit from this testability feature because we should be more confident to change working code with regression testing. Also external factors such as SOX compliance  make it important for the business to assemble test evidence. Testable systems certainly can aid .&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Design For testability&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;To  increase both the ease and value of testing we can tack different areas of the software development process and the software product itself. For example&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The software development methodology (“testable” requirement concept, etc) &lt;/li&gt;&lt;li&gt;The software technology (Procedural vs. Object-Oriented, Mainframe, etc )&lt;/li&gt;&lt;li&gt;The software architecture &amp;amp; design (Layered vs. monolithic, Coupling , Encapsulation , etc)&lt;/li&gt;&lt;li&gt;The code (Assertions , mocks/stubs , etc )&lt;/li&gt;&lt;li&gt;Tool support (Automation ,  Xunit framework , etx)&lt;/li&gt;&lt;li&gt;The developer (Training and education , code reviews , etc)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This broad spectrum calls for an holistic approach of course. The test context will put certain focus in that approach. For example&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;For functional testing you need good test reference in form requirements documents to establish your test cases&lt;/li&gt;&lt;li&gt;For System testing , you must  be able to let system work under operational condition together with data and sometimes external systems. &lt;/li&gt;&lt;li&gt; For developer  testing , you must sometimes be able test your unit in isolation and sometimes you would like to integrate a set of unit together.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Currently I'm interested in the developer testing context . So if you have experiences in raising the testability of your code and wish to share them , please do so. I would to hear from you how dependency injection help you ( or not) , how unit testing helped you find defects easily , etc.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3235191856994357104?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3235191856994357104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3235191856994357104' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3235191856994357104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3235191856994357104'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/05/design-for-testability.html' title='Design for Testability'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-5646615259522117337</id><published>2008-05-13T11:58:00.000+02:00</published><updated>2008-05-13T12:08:06.401+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Architecture'/><title type='text'>Application taxonomies</title><content type='html'>&lt;p&gt;A classification of software application can help you to think about an architecture and/or determine a reference architecture in your catalogue.&lt;br /&gt;Multiple characteristics can be used to set up a taxonomy. These taxonomies can help you I think because it sets up a context for making a software architecture and the usage of reference architectures. Usually one classification criterion alone doesn’t fit the entire application . Multiple axes.&lt;br /&gt;&lt;br /&gt;I think one of the main message would be : Don’t be fooled that one reference architecture can be used in all scenarios.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Front-end technology&lt;/strong&gt;&lt;br /&gt;o Windows (classic / touch screen)&lt;br /&gt;o Web-based (classic / Rich Internet client )&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Distribution&lt;/strong&gt;&lt;br /&gt;o Desk-top&lt;br /&gt;o Mobile/PDA&lt;br /&gt;o Sever&lt;br /&gt;o Distributed&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Connected&lt;/strong&gt;&lt;br /&gt;o On-line&lt;br /&gt;o Disconnected with on-line capabilities (smart client)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Communication&lt;/strong&gt;&lt;br /&gt;o Asynchronous&lt;br /&gt;o Synchronous&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Target &lt;/strong&gt;&lt;br /&gt;o Consumer ( E-commerce, PDA)&lt;br /&gt;o Business (Traditional administrative data keeping or/and decision support)&lt;br /&gt;o Industry (MES, CIM, MRP, SCADA, real-time systems, PLC, Robotics)&lt;br /&gt;o Government E-government&lt;br /&gt;o Entertainment (Games)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Connectivity&lt;/strong&gt;&lt;br /&gt;o Internet&lt;br /&gt;o LAN&lt;br /&gt;o WAN&lt;br /&gt;o VPN&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Function&lt;/strong&gt;&lt;br /&gt;o OLTP applications&lt;br /&gt;o Reporting applications ,Data warehouse, BI&lt;br /&gt;o Batch application&lt;br /&gt;o Service–oriented apps&lt;br /&gt;o Mobile device applications&lt;br /&gt;o Integration Applications ( ERP, Mainframe , etc)&lt;br /&gt;o Office applications and Office integration&lt;br /&gt;o Portals&lt;br /&gt;o System software&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Organisation boundaries&lt;/strong&gt;&lt;br /&gt;o Departmental&lt;br /&gt;o organisation&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Usage pattern&lt;/strong&gt;&lt;br /&gt;o Collaboration&lt;br /&gt;o Transactional, data keeping&lt;br /&gt;o Decision support&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Time pattern&lt;/strong&gt;&lt;br /&gt;o Long running “transactions” (Workflow)&lt;br /&gt;o Short running business transactions&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Expected life-time&lt;/strong&gt;&lt;br /&gt;o Short-term&lt;br /&gt;o Long term&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Business area&lt;/strong&gt;&lt;br /&gt;o Medical&lt;br /&gt;o Financial&lt;br /&gt;o Government&lt;br /&gt;o Industry&lt;br /&gt;o Commerce&lt;br /&gt;o Etc&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Saas&lt;/strong&gt; (Software as a Service ) software.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Etc.&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;What do you think? &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-5646615259522117337?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/5646615259522117337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=5646615259522117337' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/5646615259522117337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/5646615259522117337'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/05/application-taxonomies.html' title='Application taxonomies'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3956845258832417186</id><published>2008-05-13T11:42:00.001+02:00</published><updated>2008-08-27T15:53:24.201+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Architecture'/><title type='text'>Software architecture decisions</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I recently had to give a definition of what a software architecture is . Not always that easy because Software Architecture is a much loaded term. If you want some formal definitions what a software architecture is , I recommend reading the information on &lt;a href="http://www.sei.cmu.edu/architecture/published_definitions.html#Modern"&gt;http://www.sei.cmu.edu/architecture/published_definitions.html#Modern&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;General tone in these definitions is that you need to make high-level decisions about the system you' re going to build;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;What style are you going to use? What is the structure? &lt;/li&gt;&lt;li&gt;How is it going to function? How do structural components of the architecture work together? &lt;/li&gt;&lt;li&gt;How does it meet the needs of all the stakeholders?&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These &lt;strong&gt;high-level decisions&lt;/strong&gt; have a high impact on the application. You can not change them easily if wanted or needed. Unless you’re prepared to put enough resources on the table.&lt;br /&gt;&lt;br /&gt;In the bullets below I tried to sum up the different aspects of a software architecture. This list is not intended to be exhaustive.&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Windows front-end or web front-end ( Rich Internet clients)&lt;/li&gt;&lt;li&gt;Layering, organization of code, separation of concerns, &lt;/li&gt;&lt;li&gt;Representing “business objects” persisted in a database&lt;/li&gt;&lt;li&gt;Exposed domain model or using Data transfer Objects / Presentation Model&lt;/li&gt;&lt;li&gt;DataSets versus classic classes&lt;/li&gt;&lt;li&gt;Organization of “back-end” logic&lt;/li&gt;&lt;li&gt;Organization of “Presentation” logic&lt;/li&gt;&lt;li&gt;Organization of “data-access” logic&lt;/li&gt;&lt;li&gt;Distribution or not&lt;/li&gt;&lt;li&gt;Remoting technology&lt;/li&gt;&lt;li&gt;Authentication, authorization, Audit&lt;/li&gt;&lt;li&gt;Data binding&lt;/li&gt;&lt;li&gt;Synchronous / asynchronous&lt;/li&gt;&lt;li&gt;ORM tools or raw ADO.NET&lt;/li&gt;&lt;li&gt;Multi-language&lt;/li&gt;&lt;li&gt;Exception handling versus status code&lt;/li&gt;&lt;li&gt;Instrumentation /Logging&lt;/li&gt;&lt;li&gt;Configuration&lt;/li&gt;&lt;li&gt;Caching&lt;/li&gt;&lt;li&gt;Database schema fixed or freely adaptable to need of design designs&lt;/li&gt;&lt;li&gt;Long-running “transactions” (conversations)&lt;/li&gt;&lt;li&gt;Reporting needs&lt;/li&gt;&lt;li&gt;Validation rules placement (Attribute based, Intra object based, Inter object based)&lt;/li&gt;&lt;li&gt;Etc.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;It is important to take &lt;strong&gt;holistic&lt;/strong&gt; approach towards the desicions. You will need to take some trade-offs and influencing criteria into account.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Kind of application built (taxonomy)&lt;/li&gt;&lt;li&gt;Tooling can constrain how you organize your application (code generators, frameworks, application building blocks, software factories ,etc)&lt;/li&gt;&lt;li&gt;Availability/knowledge of people can constrain the “feasibility” of your architecture&lt;/li&gt;&lt;li&gt;Process (top-down versus bottom up, behaviour-centric versus data-centric)&lt;/li&gt;&lt;li&gt;External / internal regulation can influence your architecture (SOX, internal Audit rules&lt;/li&gt;&lt;li&gt;Availability of reference architecture.&lt;/li&gt;&lt;li&gt;Non-functional requirements&lt;/li&gt;&lt;li&gt;Patterns&lt;/li&gt;&lt;li&gt;Time-to-Market&lt;/li&gt;&lt;li&gt;etc.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;If I missing some points or you want to comment on this. Please feel free.&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3956845258832417186?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3956845258832417186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3956845258832417186' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3956845258832417186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3956845258832417186'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/05/software-architecture-decisions.html' title='Software architecture decisions'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-6038325124616396222</id><published>2008-04-23T14:34:00.000+02:00</published><updated>2008-04-24T07:53:13.561+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO Entity Framework'/><title type='text'>Comparing to Linq to SQL</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;Recently I took some time to investigate Entity Framework (CTP3) and Linq to SQL (RTM) further. While going through the examples I compiled following list with benefits &amp;amp; concerns. Maybe you have made a list for your own? Maybe you would care to comment. Please do so!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Linq to SQL&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Benefits&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Already available in VS2008 RTM&lt;/li&gt;&lt;li&gt;Generation of partial classes based on the database schema&lt;/li&gt;&lt;li&gt;Relationship are also detected and modelled as special properties in the entity classes&lt;/li&gt;&lt;li&gt;You work with these entity classes in you application.&lt;/li&gt;&lt;li&gt;Generated classes can be augmented with custom methods&lt;/li&gt;&lt;li&gt;Generated classes can be augmented with partial methods&lt;/li&gt;&lt;li&gt;LINQ support to specify queries&lt;/li&gt;&lt;li&gt;Dynamic generation of SQL (you do not have to write SQL your self)&lt;/li&gt;&lt;li&gt;Databinding support&lt;/li&gt;&lt;li&gt;Lazy loading (default) and immediate loading flexibility&lt;/li&gt;&lt;li&gt;Updating only changed columns&lt;/li&gt;&lt;li&gt;Optimistic Concurrency support through mapping directives.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Concerns&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Basis mapping capabilities ( 1 table -&gt; 1 Entity)&lt;/li&gt;&lt;li&gt;Only SQLServer&lt;/li&gt;&lt;li&gt;Distributed application requires special attention (dataContext)&lt;/li&gt;&lt;li&gt;Designer lets you start from a blank model but I haven't found something to create a database schema from the entity model.&lt;/li&gt;&lt;li&gt;Serialization of entity classes only set if generated with SQLMetal command-line tool option.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Entity Framework&lt;/h2&gt;&lt;h3&gt;Benefits&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Generation of partial classes based on the database schema&lt;/li&gt;&lt;li&gt;Designer lets you start from a blank model but I haven't found something to create a database schema from the entity model.&lt;/li&gt;&lt;li&gt;You work with these entity classes in you application.&lt;/li&gt;&lt;li&gt;Generated classes can be augmented with custom methods&lt;/li&gt;&lt;li&gt;LINQ support to specify queries&lt;/li&gt;&lt;li&gt;Dynamic generation of SQL (you do not have te write SQL your self)&lt;/li&gt;&lt;li&gt;Databinding support&lt;/li&gt;&lt;li&gt;Normally foreseen to accommodate multiple database systems&lt;/li&gt;&lt;li&gt;More flexible mapping capabilities than Linq To SQL (fine-grained entity model, Inheritance mapping flexibility, etc)&lt;/li&gt;&lt;li&gt;Generated classes by default serializable&lt;/li&gt;&lt;li&gt;Data driven Object-modelling point of view&lt;/li&gt;&lt;li&gt;Lazy loading (default) and immediate loading flexibility&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Concerns&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Promised to be shipped with SP1 VS2008&lt;/li&gt;&lt;li&gt;Distributed application requires special attention (ObjectContext)&lt;/li&gt;&lt;li&gt;Designer lets you start from a blank model but I haven't found something to create a database schema from the entity model.&lt;/li&gt;&lt;li&gt;In the designer you can not add behaviour in the model( somewhat normal because it is a DSL for data persistence but still....). Entity are now more geared towards a data-container role.&lt;/li&gt;&lt;li&gt;Two flavours to query the databases system (linq to entities and entity SQL). At this moment I'm not very sure when to use which.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So if you have other points of interest or remarks , I would like to hear them.&lt;/p&gt;&lt;p&gt;Thanks in advance.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-6038325124616396222?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/6038325124616396222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=6038325124616396222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6038325124616396222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6038325124616396222'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/04/comparing-to-linq-to-sql.html' title='Comparing to Linq to SQL'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-9114343015416877464</id><published>2008-04-05T16:18:00.000+02:00</published><updated>2008-04-06T22:25:24.518+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WCF'/><title type='text'>VISUG Event (03 April 2008): WCF - Beyond endpoint - Juval Löwy</title><content type='html'>WCF : A brave new world&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Belgian Visual Studio User group (VISUG) had invited no one less than Juval Löwy to present a session on WCF Juval is an authority on the subject and is/was? a member of the advisory comitee of WCF. From the summary on the VISUG website (&lt;a href="http://www.visug.be/"&gt;http://www.visug.be/&lt;/a&gt;) you could tell that this wasn't going to be your typical WCF 200 type of presentation (or 300 or 400 for that matter).&lt;br /&gt;&lt;br /&gt;Juval immediately set the tone of his presentation (or should I say show) by stating that WCF is a better .NET . WCF will deprecate .NET. During the next hour and a half it took the audience the numerous of demo apps to make his point.&lt;br /&gt;&lt;br /&gt;WCF is the next development platform according the Juval. He pushed it a little bit further by saying Microsoft is masquerading this "Truth" from us. He mentions the whole marketing message Microsoft put behind the start of the first version of .NET : .Net is the platform to build web services. We all learned in time that there is much more than web services to .NET. This was primarily done to soothe the organisations and companies that just spent tons of money in making their developers COM- savvy and converted their applications to VB6 / C++ ATL/ COM + . Don't worry, people. We have got this new thing here but it is for web services. Don't be alarmed. By the way we have created VB.NET . You already know half. And yes there were migration wizards and .NET - COM interoperability features. In the end .NET was not so easy ...&lt;br /&gt;&lt;br /&gt;Comes along WCF: ....It is a new breed of communications infrastructure built around the Web services architecture ... (&lt;a href="http://msdn2.microsoft.com/nl-be/netframework/aa663324(en-us).aspx"&gt; MSDN site&lt;/a&gt;) Again they stress onto web services (although the term connected systems is more present in the WCF literature on MSDN) . Again to soothe the companies that have invested in their developers to learn ASP.NET web services but also other technologies like Messaging (MSMQ) , .NET remoting, Enterprise services (COM+). Again ...don't be alarm folks, it is only about web services.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Juval has more visionary message to tell regarding WCF. We are standing again on the foothill of a big mountain. We at the brink of a new paradigm shift. A service-orientation, declarative program model we you , if you like, also can create web services. But the granularity of what a service might be is not solely at level of web services. According to Juval the interception mechanism of the WCF run time can be used at every class. WCF everywhere is the nirvana. At least to Juval. I don't know if he really meant that or just wanted to keep us on the edge. I think the message was as your class need certain services (security, reliability, transactions, etc) And WCF can offer them , why need turn your class into a "service" and leave to plumbing to WCF.&lt;br /&gt;To me that was the thing I learned from the presentation. Don't ever write plumbing code yourself, leave it to the experts. Concentrate on the domain logic.&lt;br /&gt;&lt;br /&gt;With a few smart examples he showed us the essence of what WCF can give to you . And the sheer power you sometimes get by just changing the config settings or changing an attribute on a class ( or should I say service). Some of things you of course could do with regular .NET but the amount of effort and knowledge you need to have to do so are so big ,that it can be difficult to defend not using the out-of-the-box features of WCF. And don't talk about the testing effort and maintenance effort you have to put into all this plumbing code (your customer hasn't asked you for in the first place. After the session we al received the &lt;a href="http://www.idesign.net/idesign/ContactForms/MoreInformation.aspx?Service=OnSiteTraining&amp;amp;Class=WCF"&gt;WCF resource CD &lt;/a&gt;from IDesign with lots of demo's.&lt;br /&gt;&lt;br /&gt;But the again developers love to know how things work ( so they can share this "wisdom" with the world in for example VISUG event ...or blogs :-) They love make their own stuff. But like Juval said "By giving a VB programmer the ability the use over the threading library is like giving a child a hand full of blades. They will bleed to dead. " But he immediately added "C++ don't always do it better. They are only more used to seeing blood."&lt;br /&gt;&lt;br /&gt;Sometimes we act more as "Google-programmers" . We (me included) look something up . Bend it and shape it a little so it works for us; Put the name of the original author on it and carry on. Sometimes not really really understanding what is going on under the hood. Disasters lurk around the corner.&lt;br /&gt;&lt;br /&gt;WCF takes responsibility for all that hard plumbing code . You never should create it on your own (except if you are the plumber). In WCF you actually don't see any plumbing code. All its powers get unleashed by configuration and attributes. Will not writing the infrastructure code yourself doesn't mean you don't need to understand conceptually what is going own or what the annotations are for. In fact Juval mentions that we need to think about the design more than ever but we do not necessarly write it our selves (as application programmer) . The paradigm shift maybe needs a somewhat different approach to the design process and the way we need to structure our applications.&lt;br /&gt;&lt;br /&gt;This is the foothill Juval is talking about. Of course he can offer that guidance :-) He wrote a book on the subject (&lt;a href="http://www.oreilly.com/catalog/9780596526993/"&gt;Programming WCF Services&lt;/a&gt;) and gives master classes on the &lt;a href="http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=0&amp;amp;tabid=20"&gt;WCF &lt;/a&gt;and&lt;a href="http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=0&amp;amp;tabid=20"&gt; Service Orientation&lt;/a&gt; in his own company &lt;a href="http://www.idesign.net/"&gt;IDesign&lt;/a&gt; .&lt;br /&gt;&lt;br /&gt;So enter this brave new world of service orientation. It may like a class but offers so much more . A whole application of services , all running in their own "process" giving you a lot of infrastruture functionality right out of the box.&lt;br /&gt;&lt;br /&gt;Still I have some concerns.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Focus on your own domain code. Leave plumbing to someone else. We heard that one several occasions and other (non-Microsoft) technologies before. In fact in 1996 when Microsoft transaction Server was released as part of option pack for NT4, you already had that notion of interception. In COM+ additional "services" were made available to "objects" hosted in the COM+ space. What is different now? Yes of cours WCF can do lots more. But still COM has been deprecated. (Has it? Office is still COM isn't it ?) and .NET came along. Now WCF is there. &lt;/li&gt;&lt;li&gt;Companies have invested lots of money in applications running on previous . Programmers have invested time in learning these technologies. Now we have to learn something new again ! Of course in each branch there is a progressing insight how things work and how problems can be solved. Our business the pace is somewhat quicker. If you come to think about it .NET started somewhere in 2001-2002. Time for something new thus . Maybe this is another reason not (as a application developer) get too deep into the nitty-gritty details of something although I must admit... I too like to know how things work). We should concentrate on acquiring domain knowledge or the skill to translate requirements to the platform . So actually the abstraction gap between the real world needs we translate into an information system and the actual code bits gets pushed from both side of the gap. On the one hand coding it becomes more clear, no nuisance of infrastructure code. On the other the whole model-driven movement is trying to find a way to abstract the requirements in such a way "machinery" can kick in to produce the (part) of the code. I think both efforts will find its way to each other. ( Entity Framework, Web Service Factory Modelling edition, Volta, Oslo) . I wonder how this all stand against "agile development"? Are these opposites?&lt;/li&gt;&lt;li&gt;Technology is one thing. Process (design , methodology) and people are other big variables in the equation. Or maybe synergy is a better word. How will WCF affect our design process. What skills do I need to learn understand WCF and correctly apply WCF. How to do I architect my apps?&lt;/li&gt;&lt;li&gt;Besides development there is also the operations side. How will this be affected?&lt;/li&gt;&lt;li&gt;Is WCF everywhere actually feasible with the current WCF. Juval made a special &lt;a href="http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=5&amp;amp;tabid=11"&gt;in proc factory&lt;/a&gt; to ease some of the config burden. Will this be enough to ease configuration (XML hell ) Will it not be too slow?&lt;/li&gt;&lt;li&gt;Why is an outside expert promoting this vision? Where are the Microsoft Evangelists? Where is Don Box actually?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-9114343015416877464?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/9114343015416877464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=9114343015416877464' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/9114343015416877464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/9114343015416877464'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/04/visug-event-03-april-2008-wcf-beyond.html' title='VISUG Event (03 April 2008): WCF - Beyond endpoint - Juval Löwy'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3022084467474318320</id><published>2008-03-19T21:41:00.000+01:00</published><updated>2008-03-19T22:30:25.830+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio Extensibility'/><title type='text'>Microsoft Software Factory Portfolio</title><content type='html'>&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The Software Factories provide you with a set of proven practices for building distributed applications. These practices are exposed through architectural overviews, patterns, how-to topics, reference implementations, automated guidance packages, and application blocks. There are several SW factories you can download today ( Web Service (WSF), Smart Client(SCSF), web client (WCSF))&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Microsoft Software Factory&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Software factories mean, different things to people: some are more academic, some are more pragmatic and more tool-focused. Like the one Microsoft is using for &lt;a href="http://msdn2.microsoft.com/en-us/library/bb871630.aspx"&gt;example &lt;/a&gt;“A software factory is a structured collection of related software assets. &lt;/li&gt;&lt;li&gt;When a software factory is installed in a development environment, it helps architects and developers predictably and efficiently create high-quality instances of specific types of applications.” &lt;/li&gt;&lt;li&gt;Although the differences, they all share some common motivator : helping the developer (or designer/architect) to get the job done in a more efficient way (time-to-market) and more with more quality. &lt;/li&gt;&lt;li&gt;MS SF is also about guidance. It should feel having an experienced person next to you and advising you what you should , when you should do it and how you should do it . In the current incarnation of SF this will translate into some menus, wizards and templates to the standard Visual Studio environment (Solution Explorer) to help developers build whatever the SF was intended for. &lt;/li&gt;&lt;li&gt;MS SF is also about automation. Capturing this expertise/best practices/guidance into integrated, automated features of Visual Studio and letting Visual Studio do some tasks in a consistent (so less error-prone) way , takes away some chores from the developer. You could say SF are about re-use but not only code but also expertise. &lt;/li&gt;&lt;li&gt;MS SF is also geared towards abstraction . The patterns and best practices to build a web service are not directly translated into code but there’s is an intermediary step. This gives you an opportunity to delay certain implementation decisions. It enforces you to think about it first. So the model is not the code but an abstraction (visual or not) of what you’re trying to establish and this data is kept and not lost. &lt;/li&gt;&lt;li&gt;The technologies that makes this possible are&lt;br /&gt;- The Guidance Automation Toolkit and its "run-time" companion Guidance Automation Extensions (GAX/GAT)&lt;br /&gt;- Domain Specific Language toolkit&lt;br /&gt;- Advancements in Visual Studio itself (Designer Integration Service) &lt;/li&gt;&lt;li&gt;The main point is that Microsoft Software factories help Software Factories help you build a specific kind of application.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Domain Specific language and DSL Toolkit&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A domain-specific language (DSL) is a programming language or executable specification language that offers, through appropriate notations and abstractions, expressive power focused on, and usually restricted to, a particular problem domain. &lt;/li&gt;&lt;li&gt;The DSL Toolkit (in the SDK) allows you to build visual interaction components that can be used from with in VS just like you would for example use a Winform Form designer. You drag &amp;amp; drop the VS-integrated graphical notations for a given model on the canvas and model the part of the application the DSL was conceived for. Later the actual code is generated for you. So the toolkits allows you to construct a custom-tailored designer for a model for a particular problem domain. &lt;/li&gt;&lt;li&gt;The main reason for this specialisation is that the more focused you are on a domain, the more specific you can make the abstractions and the better you can generate code from this models. Note that domain is not necessarily technical but also can be created for a particular sector like healthcare or finance.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Guidance Automation extensions and toolkit&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The Guidance Automation Toolkit and its "run-time" companion Guidance Automation Extensions (GAX/GAT) enable you to extent the Visual Studio 2005/2008 experience.&lt;/li&gt;&lt;li&gt;The Guidance Automation Extensions (GAX) is the runtime part that needs to be installed on the machines of the developers that want to use the Guidance Packages. &lt;/li&gt;&lt;li&gt;The Guidance Automation Toolkit (GAT) is the authoring part that helps you create the Guidance Packages and the setup projects to install them. Once you've installed GAT, you'll notice a new project type in Visual Studio called "Guidance Packages". This will contain all the packages that were installed on this machine. &lt;/li&gt;&lt;li&gt;Designed to simplify integrating reusable code into applications. &lt;/li&gt;&lt;li&gt;Allows architects to automate development activities that developers would usually have to perform manually; often by following a series of instructions. &lt;/li&gt;&lt;li&gt;By using the toolkit, architects can also ensure that repetitive and often error-prone activities are performed in a consistent manner, streamlining and accelerating the development process.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Portfolio&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Gives answer to various scenarios &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img id="BLOGGER_PHOTO_ID_5179564679287529026" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R-GCoiAX3kI/AAAAAAAAAKk/g96JhLTvILI/s400/MicrosoftSF.JPG" border="0" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Smart Client Software factory &lt;/li&gt;&lt;li&gt;Web Client Software factory &lt;/li&gt;&lt;li&gt;Web service software factory &lt;/li&gt;&lt;li&gt;Mobile Client Software Factory &lt;/li&gt;&lt;li&gt;Repository factory : The Repository Factory generates business entities, stored procedures, and repository classes based on an existing database. Can be enabled in the other factories. &lt;/li&gt;&lt;li&gt;Application Block Software Factory : Included in the Enterprise Library - guides developers through the process of creating new application blocks and extending existing Enterprise Library application blocks. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We can see a line in the advancement of Guidance and guidance automation in particular&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Zero generation : guidelines in paper form, Application block as accelerators , VS templates &lt;/li&gt;&lt;li&gt;First generation : wizard-like , modelling data is translated into code, modelling data is not kept (Smart Client Software Factory , Web Client Software factory )&lt;/li&gt;&lt;li&gt;Second generation : Integration of DSL technology, modelling data is kept (Web Service Software factory Modelling Edition )&lt;/li&gt;&lt;li&gt;Next generation : Integration multiple models&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Smart Client Software factory&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;addresses the challenges around building complex enterprise Winforms applications. As the complexity increases and the teams grow, the application becomes increasingly difficult to maintain. &lt;/li&gt;&lt;li&gt;enables designing a composite application that is composed of many discrete, loosely coupled modules. These modules can be developed, tested by separate teams. &lt;/li&gt;&lt;li&gt;Build upon the Composite Application Block (CAB) &lt;/li&gt;&lt;li&gt;Not all part are compiled together in a giant .exe file, &lt;/li&gt;&lt;li&gt;parts are more or less separately and at runtime they are compose together &lt;/li&gt;&lt;li&gt;CAB provides the “infrastructure” to support the loos-coupling&lt;br /&gt;- Microsoft.Practices.CompositeUI.dll&lt;br /&gt;- Microsoft.Practices.CompositeUI.WinForms.dll&lt;br /&gt;- Microsoft.Practices.ObjectBuilder.dll &lt;/li&gt;&lt;li&gt;Make use of Enterprise Library modules (Exceptions, Logging, Caching, Security)&lt;/li&gt;&lt;li&gt;Aim SCSF: let application developers concentrate on the “application” logic not the infrastructure part (CAB) &lt;/li&gt;&lt;li&gt;Generates consistent application infrastructure, style and logic &lt;/li&gt;&lt;li&gt;Intrinsic separation of form from function / application layers &lt;/li&gt;&lt;li&gt;Uses Model-View-Presenter pattern (Passive View Variant) &lt;/li&gt;&lt;li&gt;Integrated front-end to diverse data sources &lt;/li&gt;&lt;li&gt;Sync &amp;amp; async web services, online &amp;amp; offline capable, caching &lt;/li&gt;&lt;li&gt;Based on concept of Dependency Injection (ObjectBuilder component from Enterprise Library )&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Web Client Factory&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Similarities with SCSF in concept&lt;/li&gt;&lt;li&gt;Creates Initial Visual Studio Solution &lt;/li&gt;&lt;li&gt;Web Application Projects or Websites &lt;/li&gt;&lt;li&gt;VB or C# &lt;/li&gt;&lt;li&gt;Add View-Presenter, Business Modules, etc.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;Mobile Client Software Factory&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;for developing applications where the client is running on mobile devices such as PDAs and smart phones.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Web Service Software Factory Modelling Edition&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;This is the third version. &lt;/li&gt;&lt;li&gt;C# only&lt;/li&gt;&lt;li&gt;ASMX and WCF &lt;/li&gt;&lt;li&gt;For developing distributed applications communicating via Web services. &lt;/li&gt;&lt;li&gt;The factory uses three types of models to generate service code ; Service Contract models , Data Contract models, and Hosting models. &lt;/li&gt;&lt;li&gt;The models are visualized with special “shapes” and their corresponding properties. The look &amp;amp; feel is like the Class diagram tool in Visual Studio. So it is not UML (too generic) .&lt;/li&gt;&lt;li&gt;The designers that enable the modelling features are actually build with the DSL toolkit. For each of the three model (service, data and hosting) you get different designers. From the demo it looked very slick. &lt;/li&gt;&lt;li&gt;Extending the WSFm is possible . P&amp;amp;P identified some 11 scenarios. Some of them , like changing something in the exiting code Text templates are very easy , while other require you the download the source code for the WSFm and modify (and maintain ) it yourself.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Repository Factory&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Used to be a part of Web Service factory as the Data Access Guidance Package. &lt;/li&gt;&lt;li&gt;Now separate package that can be enabled in other packages &lt;/li&gt;&lt;li&gt;The Repository Factory generates business entities from tables in a existing database, CRUD stored procedures for each table in the database, and repository classes based on an existing database. &lt;/li&gt;&lt;li&gt;Data Mapper (Fowler) with pure ADO.NET using SPROCS &lt;/li&gt;&lt;li&gt;Multi-Database Support via Data Access Application Block &lt;/li&gt;&lt;li&gt;No Relationship Support- 1:1, 1:m, m:m &lt;/li&gt;&lt;li&gt;No Object State Tracking &lt;/li&gt;&lt;li&gt;Currency Support Only via Timestamp &lt;/li&gt;&lt;li&gt;Community Led Development on codeplex.com .&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Patterns and Practices Guidance ( &lt;a href="http://www.pnpguidance.net/"&gt;http://www.pnpguidance.net/&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Microsoft patterns &amp;amp; practices SF ( &lt;a href="http://msdn2.microsoft.com/en-us/teamsystem/aa718951.aspx"&gt;http://msdn2.microsoft.com/en-us/teamsystem/aa718951.aspx&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Software Factories: Assembling Applications with Patterns, Models, Frameworks and Tools (Jack Greenfield &amp;amp; Keith Short)&lt;/li&gt;&lt;li&gt;Compuware Belgium forum site, &lt;a href="http://intofactories.net/"&gt;http://intofactories.net/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Code generation Conference 2008 ( &lt;a href="http://www.codegeneration.net/conference/index.php"&gt;http://www.codegeneration.net/conference/index.php&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Domain-Specific Development with Visual Studio DSL Tools (Microsoft .NET Development Series) by Steve Cook, Gareth Jones, Stuart Kent, Alan Cameron Wills.&lt;/li&gt;&lt;li&gt;The EFx Architectural-Guidance Software Factory,Jezz Santos,http://msdn2.microsoft.com/en-us/library/aa905331.aspx&lt;/li&gt;&lt;li&gt;HL7 Software Factory , Mauro Regio , &lt;a href="http://softwarefactories.com/workshops/OOPSLA-2005/Papers/Regio.pdf"&gt;http://softwarefactories.com/workshops/OOPSLA-2005/Papers/Regio.pdf&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Software Factories: report from the trenches, and thoughts from p&amp;amp;p ,Edward Jezierski , http://blogs.msdn.com/edjez/&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3022084467474318320?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3022084467474318320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3022084467474318320' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3022084467474318320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3022084467474318320'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/03/microsoft-software-factory-portfolio.html' title='Microsoft Software Factory Portfolio'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/R-GCoiAX3kI/AAAAAAAAAKk/g96JhLTvILI/s72-c/MicrosoftSF.JPG' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-2256264241350691181</id><published>2008-02-22T10:15:00.000+01:00</published><updated>2008-02-22T11:23:42.387+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio Extensibility'/><title type='text'>VISUG event : Web service Software factory</title><content type='html'>&lt;p&gt;Hello ,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Belgian Visual Studio User group (VISUG) invited yesterday (21/02/2008) Olaf Conijn to give a presentation about Software Factories and the Web service Software factory modelling edition.&lt;br /&gt;&lt;br /&gt;Olaf has worked together with Microsoft patterns &amp;amp; Practices group on the Web service Software factory modelling edition (WSFm) where he was responsible for the extensibility part of the WSFm. Later he implemented Software Factories in the Netherlands (Capgemini BV). So you could not image a better person to give this presentation. Currently Olaf is trying to make the world a safer place as he's implementing software to alert the world in case of outbreaks of pandemics.( &lt;a href="http://instedd.org/"&gt;http://instedd.org/&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Olaf’s presentation was divided in several logical parts&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The “What” of Software factories&lt;/li&gt;&lt;li&gt;The “Why” of Software factories&lt;/li&gt;&lt;li&gt;The “How” of software factories in the form of demo’s of the WSFm&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some key point I got from the presentation and the talk with Olaf afterwards:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;There are many definitions of Software factories : some are more academic, some are more pragmatic and more tool-focused. Like the one Microsoft is using for example (MS SF). (&lt;a href="http://msdn2.microsoft.com/en-us/library/bb871630.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb871630.aspx&lt;/a&gt;) Although the differences, they all share some common motivator : helping the developer (or designer/architect) to get the job done in a more efficient way (time-to-market) and more with more quality. (&lt;a href="http://appdevchronicles.blogspot.com/2007/10/software-factory.html"&gt;http://appdevchronicles.blogspot.com/2007/10/software-factory.html&lt;/a&gt;) &lt;/li&gt;&lt;li&gt;MS SF is about guidance. It should feel having an experienced person next to you and advising you what you should , when you should do it and how you should do it . &lt;/li&gt;&lt;li&gt;MS SF is also about automation. Capturing this expertise/best practices/guidance into integrated, automated features of Visual Studio and letting Visual Studio do some tasks in a consistent (so less error-prone) way , takes away some chores from the developer. You could say SF are about re-use but not only code but also expertise. &lt;/li&gt;&lt;li&gt;MS SF is now also geared towards abstraction: This was very apparent in the WSFm (hence the name of course). The patterns and best practices to build a web service are not directly translated into code but there’s is an intermediary step: You model all the different parts of a web service like the MS engineers envision them. This gives you an opportunity to delay certain implementation decisions. It enforces you to think about it first. So the model is not the code but a very visual abstraction of what you’re trying to establish.&lt;/li&gt;&lt;li&gt;The models are visualized with special “shapes” and their corresponding properties. The look&amp;amp;feel is like the Class diagram tool in Visual Studio. So it is not UML (too generic) . The designers that enable the modelling features are actually build with the DSL toolkit. For each of the three model (service, data and hosting) you get different designers. From the demo it looked very slick.&lt;/li&gt;&lt;li&gt;There are several key technologies that make MS SF possible : GAX/GAT is about leveraging the automation possibilities of Visual Studio in the field guidance. DSL are geared toward modelling and code generation.&lt;br /&gt;MS Software factories come in different forms and shapes (Web client SF, Smart Client SF , Web Service SF, etc). So there isn’t a general SF that can encompass all types of applications. The main reason for this specialisation is that the more focused you are on a domain, the more specific you can make the abstractions and the better you can generate code from this models. Note that domain is not necessarily technical but also can be created for a particular sector like healthcare or finance.&lt;/li&gt;&lt;li&gt;Extending the WSFm is possible . P&amp;amp;P identified some 11 scenarios. Some of them , like changing something in the exiting code Text templates are very easy , while other require you the download the source code for the WSFm and modify (and maintain ) it yourself.&lt;/li&gt;&lt;li&gt;You can even build your own SF. Olaf figures , based on own experiences in the Netherlands, that make a SF is 2 to 3 times more expensive than building the product that the SF has to build (if I understood him correctly). &lt;/li&gt;&lt;li&gt;So building a SF only makes sense if you build multiple applications based on the same architectural principles that the SF enforces. Olaf estimates that you earn the SF build back if you “sell” 5 project build with SF. So you only should invest in SF you expect “economies of scale”&lt;/li&gt;&lt;li&gt;If you embark on a “journey/ordeal” to make your own SF , be sure to have “domain” experts at hand, be technical or functional in nature.&lt;/li&gt;&lt;li&gt;But building a SF doesn’t have to automate everything . You can also make more “pragmatic” SF that only focus on very explicit stuff your trying to implement. For example creating a skeleton for a solution with the GAX/GAT&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some concerns ( expressed in the form : “I wish I knew how to …”)&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;H2 assess the adoption grade of MS SF in organization…. And this is not the same as announcing the number of downloads :-)&lt;/li&gt;&lt;li&gt;H2 assess the importance in MS SF in the big scheme of development tools at MS. MS SF came out of the P&amp;amp;P group. One of the key technologies GAX/GAT) has been a CTP for a long time (sine 2005) . It just recently got the label release. As far I can tell the DSL (another key technology) is maintained by another group. Why are these technologies not in the Visual Studio release cycle?&lt;/li&gt;&lt;li&gt;H2 integrate VB.NET into the WSFm. In the version (I presume the latest at the time) we show you could not select VB.NET as your language. When Olaf added a WCF implementation in created a c# project. According to him , you only need to translate the text templates. If it is so easy , why didn’t P&amp;amp;P do it for us?&lt;/li&gt;&lt;li&gt;H2 find proper “guidance” to build “guidance tools” with GAT and DSL besides books and blogs.&lt;/li&gt;&lt;li&gt;H2 cope with generated code, your own code and the model (keeping it synchronized).&lt;/li&gt;&lt;li&gt;H2 position agile techniques with model-driven development. Are they opposites or do the complemented each other ?&lt;/li&gt;&lt;li&gt;H2 interpret the disappearance of the data access wizard in the previous versions of the WSF (at least I didn’t see it in the demos). These wizards enabled you to generate data access code and business entities. Maybe the advent of Linq to SQL an the Entity data framework have something to do with it.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some references mentioned (or I heard from other participants)&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Microsoft patterns &amp;amp; practices SF ( &lt;a href="http://msdn2.microsoft.com/en-us/teamsystem/aa718951.aspx"&gt;http://msdn2.microsoft.com/en-us/teamsystem/aa718951.aspx&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Software Factories: Assembling Applications with Patterns, Models, Frameworks and Tools (Jack Greenfield &amp;amp; Keith Short)&lt;/li&gt;&lt;li&gt;Compuware Belgium SF focus group: &lt;a href="http://intofactories.net/"&gt;http://intofactories.net/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Code generation Conference 2008 ( &lt;a href="http://www.codegeneration.net/conference/index.php"&gt;http://www.codegeneration.net/conference/index.php&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Domain-Specific Development with Visual Studio DSL Tools (Microsoft .NET Development Series) by Steve Cook, Gareth Jones, Stuart Kent, Alan Cameron Wills.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Maybe you some own thoughts or opions? Be sure to drop a line ....&lt;/p&gt;&lt;p&gt;Thanks to VISUG for inviting people like Olaf to Belgium. Be sure to keep an eye on the VISUG site (&lt;a href="http://www.visug.be/"&gt;http://www.visug.be/&lt;/a&gt;) because the one of the next speaker will be none less than Juval Lowy. Keep up the good work.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-2256264241350691181?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/2256264241350691181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=2256264241350691181' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/2256264241350691181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/2256264241350691181'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/02/visug-event-web-service-software.html' title='VISUG event : Web service Software factory'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-6363918867663824727</id><published>2008-02-14T08:25:00.000+01:00</published><updated>2008-02-14T10:09:53.829+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Office Business Applications'/><title type='text'>Stay in the comfort zone with OBA</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;Yesterday (13/02/2008) I attended a MSDN evening organised by Microsoft Belgium about &lt;strong&gt;Office Business Applications&lt;/strong&gt; (OBA). &lt;strong&gt;Serge Luca&lt;/strong&gt; from U2U and MVP for Connected Systems gave an overview about OBA from a development perspective . He had also plenty of demo’s available. Too bad his time was limited.&lt;br /&gt;&lt;br /&gt;This is what I remembered from it.&lt;br /&gt;&lt;br /&gt;OBA are applications that leverage the Office Suite applications beyond their out-of-the box capabilities and integrate them with other systems in your organisation (&lt;strong&gt;L&lt;/strong&gt;ine-&lt;strong&gt;O&lt;/strong&gt;f-&lt;strong&gt;B&lt;/strong&gt;usiness Apps).&lt;br /&gt;&lt;br /&gt;The key driver for leveraging Office is to let users stay in their “&lt;strong&gt;comfort zone&lt;/strong&gt;”. While organisations have invested large amounts in the user experience in packaged and custom applications , users still like to work in their familiar Office tools. Even the advent of web-enabling all the LOBs didn’t stop users from for example pumping SAP data into Excel and use it from there on. The user-experience the people get from Office tools is unbeatable.&lt;br /&gt;&lt;br /&gt;That’s why Microsoft made &lt;strong&gt;Office 2007 System&lt;/strong&gt; a truly development platform to enable developers to create OBA. The technology enablers are not only situated on the client side (i.e. Office Apps themselves) but also on the server side. For example you can extend the Office user interface (ribbon extension, task panes, Outlook from region) . Thanks to the Office open XML format you can intervene in the documents at file-level . This open possibility to programmatic creation of for example word documents. You even don’t need a Word instance on the server. Infopath enable the creation of electronic forms. Sharepoint and related technologies are the enablers to create workflow oriented applications and extend the content document capabilities of Sharepoint. The Business data Catalog makes it easier to retrieve and search information that is already available in ERP systems or databases.&lt;br /&gt;And all this technology can be unleashed through one development environment ; &lt;strong&gt;Visual Studio 2008&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;In final part of his presentation Serge mentioned 6 basic &lt;strong&gt;OBA patterns&lt;/strong&gt; or scenario’s if you will. Unfortunately he didn't have the time to go through them but the demo’s he showed , were actually implementation of these 6 patterns. A book he highly recommends in that respect is 6 Microsoft Office Business Applications for Office SharePoint Server 2007 from Microsoft Press .&lt;br /&gt;&lt;br /&gt;So if you think Office Development is only about VBA (which is still possible by the way) , think again and check out &lt;a href="http://www.obacentral.com/"&gt;http://www.obacentral.com/&lt;/a&gt;. Or like Serge said : "Let's Rock 'n' Roll (with OBA)"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alexander&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-6363918867663824727?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/6363918867663824727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=6363918867663824727' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6363918867663824727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6363918867663824727'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/02/stay-in-confort-zone-with-oba.html' title='Stay in the comfort zone with OBA'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-5668612008276680827</id><published>2008-02-13T14:47:00.000+01:00</published><updated>2008-02-13T16:28:04.147+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><title type='text'>Don’t bother System testers with programming errors.</title><content type='html'>Hello ,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Suppose you're a team lead on a project and you take a look in your bug tracking tool one fine morning. You see that the tester on the team has filled some bugs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5166464678036718434" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" height="354" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/R7L4QGb7Q2I/AAAAAAAAAKc/PuBWw2VorQw/s400/bugtracker.bmp" width="535" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here are some details of it:&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;style&gt;body {font-family: verdana, arial; font-size: 10pt; background: #ffffff; }&lt;br /&gt;td {font-size: 8pt;}&lt;br /&gt;p {font-size: 10pt;}&lt;br /&gt;&lt;br /&gt;a {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:visited {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:hover {color:#ff6633; font-size: 10pt; text-decoration: none; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* bug tables */&lt;br /&gt;&lt;br /&gt;.bugt {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* bug table headers */&lt;br /&gt;&lt;br /&gt;.bugh {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #dddddd;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* filter row in bug table heading */&lt;br /&gt;&lt;br /&gt;.bugf {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #dddddd;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* table cell for bug table */&lt;br /&gt;.bugd {&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	border: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* other tables, like list of users, projects */&lt;br /&gt;&lt;br /&gt;.datat {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table headers */&lt;br /&gt;.datah {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table cell */&lt;br /&gt;.datad {&lt;br /&gt;background: #ffffff;&lt;br /&gt;vertical-align: top;&lt;br /&gt;border: 1px solid #aaaaaa;&lt;br /&gt;padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.err {&lt;br /&gt;	color: red;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.btn {&lt;br /&gt;	background: #ffeeaa;&lt;br /&gt;	color: #0000ff;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menubar {&lt;br /&gt;	background: #f0fff0;&lt;br /&gt;	padding: 0px;&lt;br /&gt;	border-bottom: 1px solid #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt {&lt;br /&gt;	background:white;&lt;br /&gt;	border: 1px #009900 solid;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt_text {&lt;br /&gt;	font-family:courier;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.pst {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	color: darkgreen;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.listitem {&lt;br /&gt;	color: #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.smallnote {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.logo {&lt;br /&gt;	background: #00cc00;&lt;br /&gt;	font-family: arial;&lt;br /&gt;	padding: 5px;&lt;br /&gt;	color: white;&lt;br /&gt;	font-size: 12pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.lbl {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.static {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.frm {&lt;br /&gt;	padding-top: 6px;&lt;br /&gt;	padding-left: 6px;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	background: #f3f3f3;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.align {&lt;br /&gt;	text-align: left;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.gray_link {&lt;br /&gt;	color: #999999; font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menu_item {}&lt;br /&gt;.selected_menu_item {&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.click_to_sort {&lt;br /&gt;	font-size: 7pt; color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.buglist_popup {&lt;br /&gt;	z-index: 111;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	position:absolute; top:0; left:0;&lt;br /&gt;	background:#ccffcc;&lt;br /&gt;	color:black;&lt;br /&gt;	display:none;&lt;br /&gt;	width: 500;&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-family: verdana;&lt;br /&gt;	text-overflow: clip;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.suggest_select {&lt;br /&gt;	font-size:8pt;&lt;br /&gt;	background: #ccffcc;&lt;br /&gt;	border: 1px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	color: #666666;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: yellow;&lt;br /&gt;	color: red;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.tab_btn&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;	&lt;br /&gt;	border-top: 1px silver solid;&lt;br /&gt;	border-left: 1px silver solid;&lt;br /&gt;	border-bottom: 2px black solid;&lt;br /&gt;	border-right: 2px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.tab_btn_pushed&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;&lt;br /&gt;	border-top: 2px black solid;&lt;br /&gt;	border-left: 2px black solid;&lt;br /&gt;	border-bottom: 1px silver solid;&lt;br /&gt;	border-right: 1px silver solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.private {font-size: 7pt; color:red; font-weight: bold; letter-spacing: 3px;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;option {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;input  {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul&lt;br /&gt;{&lt;br /&gt;	list-style: none;&lt;br /&gt;	padding-left: 0px;&lt;br /&gt;	margin-left: 0px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul li&lt;br /&gt;{&lt;br /&gt;	margin-bottom: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.wht {margin: auto; display: block; width:40%; height:80%; border: 1px solid #cccccc;}&lt;br /&gt;.red {margin: auto; display: block; width:40%; height:80%; background: red; border: 1px solid red;}&lt;br /&gt;.grn {margin: auto; display: block; width:40%; height:80%; background: #33ff33; border: 1px solid #33ff33;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;Use this, btnet_edit_bug.css and btnet_search.css to customize your look.&lt;br /&gt;For the overall look, use this file to override what btnet_base.css says.&lt;br /&gt;&lt;br /&gt;For position, use btnet_edit_bug.css and btnet_search.css are seperate so that if you want to change&lt;br /&gt;the positioning of elements, you can do so on those two pages independently,&lt;br /&gt;without changes in one breaking the other.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;You can use css to display different priorities and statuses in different fonts, etc.&lt;br /&gt;See the "demo use of css classes" query.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;.pr1_st1 {color: red;}&lt;br /&gt;.pr1_st2 {background: yellow;}&lt;br /&gt;.pr2_st1 {font-weight: bold; color: purple;}&lt;br /&gt;.pr2_st2 {font-style: italic; background: orange;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Use these to hide fields you aren't using&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;#project_label {display:none;}&lt;br /&gt;#current_project {display:none;}&lt;br /&gt;#change_project_label {display:none;}&lt;br /&gt;#project {display:none;}&lt;br /&gt;&lt;br /&gt;#category_label {display:none;}&lt;br /&gt;#category {display:none;}&lt;br /&gt;&lt;br /&gt;#priority_label {display:none;}&lt;br /&gt;#priority {display:none;}&lt;br /&gt;&lt;br /&gt;#status_label {display:none;}&lt;br /&gt;#status {display:none;}&lt;br /&gt;&lt;br /&gt;#assigned_to_label {display:none;}&lt;br /&gt;#assigned_to_username {display:none;}&lt;br /&gt;#reassign_label {display:none;}&lt;br /&gt;#assigned_to {display:none;}&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;a {text-decoration: underline; }&lt;br /&gt;a:visited {text-decoration: underline; }&lt;br /&gt;a:hover {text-decoration: underline; }&lt;br /&gt;&lt;/style&gt;&lt;b&gt;Bug ID: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=6"&gt;6&lt;/a&gt;&lt;br /&gt;Short desc: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=6"&gt;Conversion from string "r" to type 'Double' is not valid.&lt;/a&gt;&lt;/b&gt; &lt;p&gt;&lt;table cellspacing="0" cellpadding="3" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Last changed by &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported By &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported On &lt;td&gt;2008-02-13 2:32 &lt;tr&gt;&lt;td&gt;Project &lt;td&gt;Petshop Redux &lt;tr&gt;&lt;td&gt;Organization &lt;td&gt;Omega &lt;tr&gt;&lt;td&gt;Category &lt;td&gt;bug &lt;tr&gt;&lt;td&gt;Priority &lt;td&gt;high &lt;tr&gt;&lt;td&gt;Assigned &lt;td&gt;developer &lt;tr&gt;&lt;td&gt;Status &lt;td&gt;new &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;p&gt;&lt;table cellspacing="0" cellpadding="4" border="1"&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table id="posts_table" cellspacing="3" cellpadding="0" border="0"&gt;&lt;br /&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="cmt"&gt;&lt;table width="100%"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="left"&gt;&lt;span class="pst"&gt;comment &lt;a name="6"&gt;&lt;/a&gt;6 posted by FuncTest on 2008-02-13 2:32 &lt;/span&gt;&lt;/td&gt;&lt;/td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table border="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="cmt_text"&gt;test case # 5487 Enter new Order&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Entering the non-number quantity for a certain product resulted in an error after filling out the order form. The error message was : Conversion from string "r" to type 'Double' is not valid.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There is no check for numbers ?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/table&gt;&lt;div class="align"&gt;&lt;table border="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr style="PAGE-BREAK-BEFORE: always"&gt;&lt;br /&gt;&lt;style&gt;body {font-family: verdana, arial; font-size: 10pt; background: #ffffff; }&lt;br /&gt;td {font-size: 8pt;}&lt;br /&gt;p {font-size: 10pt;}&lt;br /&gt;&lt;br /&gt;a {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:visited {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:hover {color:#ff6633; font-size: 10pt; text-decoration: none; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* bug tables */&lt;br /&gt;&lt;br /&gt;.bugt {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* bug table headers */&lt;br /&gt;&lt;br /&gt;.bugh {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #dddddd;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* filter row in bug table heading */&lt;br /&gt;&lt;br /&gt;.bugf {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #dddddd;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* table cell for bug table */&lt;br /&gt;.bugd {&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	border: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* other tables, like list of users, projects */&lt;br /&gt;&lt;br /&gt;.datat {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table headers */&lt;br /&gt;.datah {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table cell */&lt;br /&gt;.datad {&lt;br /&gt;background: #ffffff;&lt;br /&gt;vertical-align: top;&lt;br /&gt;border: 1px solid #aaaaaa;&lt;br /&gt;padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.err {&lt;br /&gt;	color: red;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.btn {&lt;br /&gt;	background: #ffeeaa;&lt;br /&gt;	color: #0000ff;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menubar {&lt;br /&gt;	background: #f0fff0;&lt;br /&gt;	padding: 0px;&lt;br /&gt;	border-bottom: 1px solid #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt {&lt;br /&gt;	background:white;&lt;br /&gt;	border: 1px #009900 solid;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt_text {&lt;br /&gt;	font-family:courier;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.pst {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	color: darkgreen;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.listitem {&lt;br /&gt;	color: #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.smallnote {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.logo {&lt;br /&gt;	background: #00cc00;&lt;br /&gt;	font-family: arial;&lt;br /&gt;	padding: 5px;&lt;br /&gt;	color: white;&lt;br /&gt;	font-size: 12pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.lbl {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.static {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.frm {&lt;br /&gt;	padding-top: 6px;&lt;br /&gt;	padding-left: 6px;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	background: #f3f3f3;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.align {&lt;br /&gt;	text-align: left;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.gray_link {&lt;br /&gt;	color: #999999; font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menu_item {}&lt;br /&gt;.selected_menu_item {&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.click_to_sort {&lt;br /&gt;	font-size: 7pt; color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.buglist_popup {&lt;br /&gt;	z-index: 111;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	position:absolute; top:0; left:0;&lt;br /&gt;	background:#ccffcc;&lt;br /&gt;	color:black;&lt;br /&gt;	display:none;&lt;br /&gt;	width: 500;&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-family: verdana;&lt;br /&gt;	text-overflow: clip;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.suggest_select {&lt;br /&gt;	font-size:8pt;&lt;br /&gt;	background: #ccffcc;&lt;br /&gt;	border: 1px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	color: #666666;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: yellow;&lt;br /&gt;	color: red;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.tab_btn&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;	&lt;br /&gt;	border-top: 1px silver solid;&lt;br /&gt;	border-left: 1px silver solid;&lt;br /&gt;	border-bottom: 2px black solid;&lt;br /&gt;	border-right: 2px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.tab_btn_pushed&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;&lt;br /&gt;	border-top: 2px black solid;&lt;br /&gt;	border-left: 2px black solid;&lt;br /&gt;	border-bottom: 1px silver solid;&lt;br /&gt;	border-right: 1px silver solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.private {font-size: 7pt; color:red; font-weight: bold; letter-spacing: 3px;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;option {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;input  {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul&lt;br /&gt;{&lt;br /&gt;	list-style: none;&lt;br /&gt;	padding-left: 0px;&lt;br /&gt;	margin-left: 0px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul li&lt;br /&gt;{&lt;br /&gt;	margin-bottom: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.wht {margin: auto; display: block; width:40%; height:80%; border: 1px solid #cccccc;}&lt;br /&gt;.red {margin: auto; display: block; width:40%; height:80%; background: red; border: 1px solid red;}&lt;br /&gt;.grn {margin: auto; display: block; width:40%; height:80%; background: #33ff33; border: 1px solid #33ff33;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;Use this, btnet_edit_bug.css and btnet_search.css to customize your look.&lt;br /&gt;For the overall look, use this file to override what btnet_base.css says.&lt;br /&gt;&lt;br /&gt;For position, use btnet_edit_bug.css and btnet_search.css are seperate so that if you want to change&lt;br /&gt;the positioning of elements, you can do so on those two pages independently,&lt;br /&gt;without changes in one breaking the other.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;You can use css to display different priorities and statuses in different fonts, etc.&lt;br /&gt;See the "demo use of css classes" query.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;.pr1_st1 {color: red;}&lt;br /&gt;.pr1_st2 {background: yellow;}&lt;br /&gt;.pr2_st1 {font-weight: bold; color: purple;}&lt;br /&gt;.pr2_st2 {font-style: italic; background: orange;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Use these to hide fields you aren't using&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;#project_label {display:none;}&lt;br /&gt;#current_project {display:none;}&lt;br /&gt;#change_project_label {display:none;}&lt;br /&gt;#project {display:none;}&lt;br /&gt;&lt;br /&gt;#category_label {display:none;}&lt;br /&gt;#category {display:none;}&lt;br /&gt;&lt;br /&gt;#priority_label {display:none;}&lt;br /&gt;#priority {display:none;}&lt;br /&gt;&lt;br /&gt;#status_label {display:none;}&lt;br /&gt;#status {display:none;}&lt;br /&gt;&lt;br /&gt;#assigned_to_label {display:none;}&lt;br /&gt;#assigned_to_username {display:none;}&lt;br /&gt;#reassign_label {display:none;}&lt;br /&gt;#assigned_to {display:none;}&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;a {text-decoration: underline; }&lt;br /&gt;a:visited {text-decoration: underline; }&lt;br /&gt;a:hover {text-decoration: underline; }&lt;br /&gt;&lt;/style&gt;&lt;b&gt;Bug ID: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=5"&gt;5&lt;/a&gt;&lt;br /&gt;Short desc: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=5"&gt;Could not find a part of the path 'c:\PetShopRedux\orders.xml'&lt;/a&gt;&lt;/b&gt; &lt;p&gt;&lt;table cellspacing="0" cellpadding="3" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Last changed by &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported By &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported On &lt;td&gt;2008-01-31 11:09 &lt;tr&gt;&lt;td&gt;Project &lt;td&gt;Petshop Redux &lt;tr&gt;&lt;td&gt;Organization &lt;td&gt;Omega &lt;tr&gt;&lt;td&gt;Category &lt;td&gt;bug &lt;tr&gt;&lt;td&gt;Priority &lt;td&gt;high &lt;tr&gt;&lt;td&gt;Assigned &lt;td&gt;developer &lt;tr&gt;&lt;td&gt;Status &lt;td&gt;new &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;p&gt;&lt;table cellspacing="0" cellpadding="4" border="1"&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table id="posts_table" cellspacing="3" cellpadding="0" border="0"&gt;&lt;br /&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="cmt"&gt;&lt;table width="100%"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="left"&gt;&lt;span class="pst"&gt;comment &lt;a name="5"&gt;&lt;/a&gt;5 posted by FuncTest on 2008-01-31 11:09 &lt;/span&gt;&lt;/td&gt;&lt;/td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table border="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="cmt_text"&gt;test case reference (#4531) : Export Open orders to xml file.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I wanted to export the open oders. Unfortunately I received the follwing error message Could not find a part of the path 'c:\PetShopRedux\orders.xml'.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When I look at my c drive I can not find a folder named PetShopRedux.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can you fix this? &lt;/span&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/table&gt;&lt;div class="align"&gt;&lt;table border="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr style="PAGE-BREAK-BEFORE: always"&gt;&lt;br /&gt;&lt;style&gt;body {font-family: verdana, arial; font-size: 10pt; background: #ffffff; }&lt;br /&gt;td {font-size: 8pt;}&lt;br /&gt;p {font-size: 10pt;}&lt;br /&gt;&lt;br /&gt;a {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:visited {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:hover {color:#ff6633; font-size: 10pt; text-decoration: none; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* bug tables */&lt;br /&gt;&lt;br /&gt;.bugt {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* bug table headers */&lt;br /&gt;&lt;br /&gt;.bugh {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #dddddd;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* filter row in bug table heading */&lt;br /&gt;&lt;br /&gt;.bugf {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #dddddd;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* table cell for bug table */&lt;br /&gt;.bugd {&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	border: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* other tables, like list of users, projects */&lt;br /&gt;&lt;br /&gt;.datat {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table headers */&lt;br /&gt;.datah {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table cell */&lt;br /&gt;.datad {&lt;br /&gt;background: #ffffff;&lt;br /&gt;vertical-align: top;&lt;br /&gt;border: 1px solid #aaaaaa;&lt;br /&gt;padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.err {&lt;br /&gt;	color: red;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.btn {&lt;br /&gt;	background: #ffeeaa;&lt;br /&gt;	color: #0000ff;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menubar {&lt;br /&gt;	background: #f0fff0;&lt;br /&gt;	padding: 0px;&lt;br /&gt;	border-bottom: 1px solid #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt {&lt;br /&gt;	background:white;&lt;br /&gt;	border: 1px #009900 solid;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt_text {&lt;br /&gt;	font-family:courier;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.pst {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	color: darkgreen;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.listitem {&lt;br /&gt;	color: #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.smallnote {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.logo {&lt;br /&gt;	background: #00cc00;&lt;br /&gt;	font-family: arial;&lt;br /&gt;	padding: 5px;&lt;br /&gt;	color: white;&lt;br /&gt;	font-size: 12pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.lbl {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.static {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.frm {&lt;br /&gt;	padding-top: 6px;&lt;br /&gt;	padding-left: 6px;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	background: #f3f3f3;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.align {&lt;br /&gt;	text-align: left;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.gray_link {&lt;br /&gt;	color: #999999; font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menu_item {}&lt;br /&gt;.selected_menu_item {&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.click_to_sort {&lt;br /&gt;	font-size: 7pt; color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.buglist_popup {&lt;br /&gt;	z-index: 111;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	position:absolute; top:0; left:0;&lt;br /&gt;	background:#ccffcc;&lt;br /&gt;	color:black;&lt;br /&gt;	display:none;&lt;br /&gt;	width: 500;&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-family: verdana;&lt;br /&gt;	text-overflow: clip;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.suggest_select {&lt;br /&gt;	font-size:8pt;&lt;br /&gt;	background: #ccffcc;&lt;br /&gt;	border: 1px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	color: #666666;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: yellow;&lt;br /&gt;	color: red;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.tab_btn&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;	&lt;br /&gt;	border-top: 1px silver solid;&lt;br /&gt;	border-left: 1px silver solid;&lt;br /&gt;	border-bottom: 2px black solid;&lt;br /&gt;	border-right: 2px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.tab_btn_pushed&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;&lt;br /&gt;	border-top: 2px black solid;&lt;br /&gt;	border-left: 2px black solid;&lt;br /&gt;	border-bottom: 1px silver solid;&lt;br /&gt;	border-right: 1px silver solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.private {font-size: 7pt; color:red; font-weight: bold; letter-spacing: 3px;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;option {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;input  {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul&lt;br /&gt;{&lt;br /&gt;	list-style: none;&lt;br /&gt;	padding-left: 0px;&lt;br /&gt;	margin-left: 0px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul li&lt;br /&gt;{&lt;br /&gt;	margin-bottom: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.wht {margin: auto; display: block; width:40%; height:80%; border: 1px solid #cccccc;}&lt;br /&gt;.red {margin: auto; display: block; width:40%; height:80%; background: red; border: 1px solid red;}&lt;br /&gt;.grn {margin: auto; display: block; width:40%; height:80%; background: #33ff33; border: 1px solid #33ff33;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;Use this, btnet_edit_bug.css and btnet_search.css to customize your look.&lt;br /&gt;For the overall look, use this file to override what btnet_base.css says.&lt;br /&gt;&lt;br /&gt;For position, use btnet_edit_bug.css and btnet_search.css are seperate so that if you want to change&lt;br /&gt;the positioning of elements, you can do so on those two pages independently,&lt;br /&gt;without changes in one breaking the other.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;You can use css to display different priorities and statuses in different fonts, etc.&lt;br /&gt;See the "demo use of css classes" query.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;.pr1_st1 {color: red;}&lt;br /&gt;.pr1_st2 {background: yellow;}&lt;br /&gt;.pr2_st1 {font-weight: bold; color: purple;}&lt;br /&gt;.pr2_st2 {font-style: italic; background: orange;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Use these to hide fields you aren't using&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;#project_label {display:none;}&lt;br /&gt;#current_project {display:none;}&lt;br /&gt;#change_project_label {display:none;}&lt;br /&gt;#project {display:none;}&lt;br /&gt;&lt;br /&gt;#category_label {display:none;}&lt;br /&gt;#category {display:none;}&lt;br /&gt;&lt;br /&gt;#priority_label {display:none;}&lt;br /&gt;#priority {display:none;}&lt;br /&gt;&lt;br /&gt;#status_label {display:none;}&lt;br /&gt;#status {display:none;}&lt;br /&gt;&lt;br /&gt;#assigned_to_label {display:none;}&lt;br /&gt;#assigned_to_username {display:none;}&lt;br /&gt;#reassign_label {display:none;}&lt;br /&gt;#assigned_to {display:none;}&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;a {text-decoration: underline; }&lt;br /&gt;a:visited {text-decoration: underline; }&lt;br /&gt;a:hover {text-decoration: underline; }&lt;br /&gt;&lt;/style&gt;&lt;b&gt;Bug ID: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=3"&gt;3&lt;/a&gt;&lt;br /&gt;Short desc: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=3"&gt;Index was outside the bounds of the array.&lt;/a&gt;&lt;/b&gt; &lt;p&gt;&lt;table cellspacing="0" cellpadding="3" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Last changed by &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported By &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported On &lt;td&gt;2008-01-31 10:38 &lt;tr&gt;&lt;td&gt;Project &lt;td&gt;Petshop Redux &lt;tr&gt;&lt;td&gt;Organization &lt;td&gt;Omega &lt;tr&gt;&lt;td&gt;Category &lt;td&gt;bug &lt;tr&gt;&lt;td&gt;Priority &lt;td&gt;high &lt;tr&gt;&lt;td&gt;Assigned &lt;td&gt;developer &lt;tr&gt;&lt;td&gt;Status &lt;td&gt;new &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;p&gt;&lt;table cellspacing="0" cellpadding="4" border="1"&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table id="posts_table" cellspacing="3" cellpadding="0" border="0"&gt;&lt;br /&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="cmt"&gt;&lt;table width="100%"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="left"&gt;&lt;span class="pst"&gt;comment &lt;a name="2"&gt;&lt;/a&gt;2 posted by FuncTest on 2008-01-31 10:38 &lt;/span&gt;&lt;/td&gt;&lt;/td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table border="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="cmt_text"&gt;test case reference (#5781) : Show overview Orders to be saved.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When i press the nenu to show me the orders that i have entered until a certain point , I get a message saying Index was outside the bounds of the array.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can you fix this? I need to test this feauture before Wednesday.&lt;/span&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/table&gt;&lt;div class="align"&gt;&lt;table border="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr style="PAGE-BREAK-BEFORE: always"&gt;&lt;br /&gt;&lt;style&gt;body {font-family: verdana, arial; font-size: 10pt; background: #ffffff; }&lt;br /&gt;td {font-size: 8pt;}&lt;br /&gt;p {font-size: 10pt;}&lt;br /&gt;&lt;br /&gt;a {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:visited {color:#0000ff; font-size: 10pt; text-decoration: none; }&lt;br /&gt;a:hover {color:#ff6633; font-size: 10pt; text-decoration: none; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* bug tables */&lt;br /&gt;&lt;br /&gt;.bugt {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* bug table headers */&lt;br /&gt;&lt;br /&gt;.bugh {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #dddddd;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* filter row in bug table heading */&lt;br /&gt;&lt;br /&gt;.bugf {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #dddddd;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* table cell for bug table */&lt;br /&gt;.bugd {&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	border: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* other tables, like list of users, projects */&lt;br /&gt;&lt;br /&gt;.datat {&lt;br /&gt;	border-collapse: collapse;&lt;br /&gt;	border-width: 1px;&lt;br /&gt;	border-style: solid;&lt;br /&gt;	border-color: #aaaaaa;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table headers */&lt;br /&gt;.datah {&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	vertical-align: top;&lt;br /&gt;	text-align: center;&lt;br /&gt;	border-top: 1px solid #aaaaaa;&lt;br /&gt;	border-bottom: 1px solid #aaaaaa;&lt;br /&gt;	border-left: 1px solid #aaaaaa;&lt;br /&gt;	border-right: 1px solid #aaaaaa;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* table cell */&lt;br /&gt;.datad {&lt;br /&gt;background: #ffffff;&lt;br /&gt;vertical-align: top;&lt;br /&gt;border: 1px solid #aaaaaa;&lt;br /&gt;padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.err {&lt;br /&gt;	color: red;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.btn {&lt;br /&gt;	background: #ffeeaa;&lt;br /&gt;	color: #0000ff;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menubar {&lt;br /&gt;	background: #f0fff0;&lt;br /&gt;	padding: 0px;&lt;br /&gt;	border-bottom: 1px solid #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt {&lt;br /&gt;	background:white;&lt;br /&gt;	border: 1px #009900 solid;&lt;br /&gt;	padding: 3px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.cmt_text {&lt;br /&gt;	font-family:courier;&lt;br /&gt;	font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.pst {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	color: darkgreen;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.listitem {&lt;br /&gt;	color: #00cc00;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.smallnote {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.logo {&lt;br /&gt;	background: #00cc00;&lt;br /&gt;	font-family: arial;&lt;br /&gt;	padding: 5px;&lt;br /&gt;	color: white;&lt;br /&gt;	font-size: 12pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.lbl {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.static {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.frm {&lt;br /&gt;	padding-top: 6px;&lt;br /&gt;	padding-left: 6px;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	background: #f3f3f3;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.align {&lt;br /&gt;	text-align: left;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.gray_link {&lt;br /&gt;	color: #999999; font-size: 10pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.menu_item {}&lt;br /&gt;.selected_menu_item {&lt;br /&gt;	font-weight: bold;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.click_to_sort {&lt;br /&gt;	font-size: 7pt; color: green;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.buglist_popup {&lt;br /&gt;	z-index: 111;&lt;br /&gt;	border-left: 1px solid silver;&lt;br /&gt;	border-top: 1px solid silver;&lt;br /&gt;	border-right: 2px solid black;&lt;br /&gt;	border-bottom: 3px solid black;&lt;br /&gt;	padding: 3px;&lt;br /&gt;	position:absolute; top:0; left:0;&lt;br /&gt;	background:#ccffcc;&lt;br /&gt;	color:black;&lt;br /&gt;	display:none;&lt;br /&gt;	width: 500;&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;	font-family: verdana;&lt;br /&gt;	text-overflow: clip;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.suggest_select {&lt;br /&gt;	font-size:8pt;&lt;br /&gt;	background: #ccffcc;&lt;br /&gt;	border: 1px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: #dddddd;&lt;br /&gt;	color: #666666;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected {&lt;br /&gt;	font-family: arial;&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;	background: yellow;&lt;br /&gt;	color: red;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.filter_selected option {&lt;br /&gt;	font-size: 7pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.tab_btn&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;	&lt;br /&gt;	border-top: 1px silver solid;&lt;br /&gt;	border-left: 1px silver solid;&lt;br /&gt;	border-bottom: 2px black solid;&lt;br /&gt;	border-right: 2px black solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.tab_btn_pushed&lt;br /&gt;{&lt;br /&gt;	padding-left: 10px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;	padding-top: 5px;&lt;br /&gt;	padding-bottom: 5px;&lt;br /&gt;	margin-top: 5px;&lt;br /&gt;	margin-bottom: 5px;&lt;br /&gt;&lt;br /&gt;	border-top: 2px black solid;&lt;br /&gt;	border-left: 2px black solid;&lt;br /&gt;	border-bottom: 1px silver solid;&lt;br /&gt;	border-right: 1px silver solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.private {font-size: 7pt; color:red; font-weight: bold; letter-spacing: 3px;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;option {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;input  {&lt;br /&gt;	font-size: 8pt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul&lt;br /&gt;{&lt;br /&gt;	list-style: none;&lt;br /&gt;	padding-left: 0px;&lt;br /&gt;	margin-left: 0px;&lt;br /&gt;	padding-right: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#edit_bug_menu ul li&lt;br /&gt;{&lt;br /&gt;	margin-bottom: 10px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.wht {margin: auto; display: block; width:40%; height:80%; border: 1px solid #cccccc;}&lt;br /&gt;.red {margin: auto; display: block; width:40%; height:80%; background: red; border: 1px solid red;}&lt;br /&gt;.grn {margin: auto; display: block; width:40%; height:80%; background: #33ff33; border: 1px solid #33ff33;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;Use this, btnet_edit_bug.css and btnet_search.css to customize your look.&lt;br /&gt;For the overall look, use this file to override what btnet_base.css says.&lt;br /&gt;&lt;br /&gt;For position, use btnet_edit_bug.css and btnet_search.css are seperate so that if you want to change&lt;br /&gt;the positioning of elements, you can do so on those two pages independently,&lt;br /&gt;without changes in one breaking the other.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;You can use css to display different priorities and statuses in different fonts, etc.&lt;br /&gt;See the "demo use of css classes" query.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;.pr1_st1 {color: red;}&lt;br /&gt;.pr1_st2 {background: yellow;}&lt;br /&gt;.pr2_st1 {font-weight: bold; color: purple;}&lt;br /&gt;.pr2_st2 {font-style: italic; background: orange;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Use these to hide fields you aren't using&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;#project_label {display:none;}&lt;br /&gt;#current_project {display:none;}&lt;br /&gt;#change_project_label {display:none;}&lt;br /&gt;#project {display:none;}&lt;br /&gt;&lt;br /&gt;#category_label {display:none;}&lt;br /&gt;#category {display:none;}&lt;br /&gt;&lt;br /&gt;#priority_label {display:none;}&lt;br /&gt;#priority {display:none;}&lt;br /&gt;&lt;br /&gt;#status_label {display:none;}&lt;br /&gt;#status {display:none;}&lt;br /&gt;&lt;br /&gt;#assigned_to_label {display:none;}&lt;br /&gt;#assigned_to_username {display:none;}&lt;br /&gt;#reassign_label {display:none;}&lt;br /&gt;#assigned_to {display:none;}&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;a {text-decoration: underline; }&lt;br /&gt;a:visited {text-decoration: underline; }&lt;br /&gt;a:hover {text-decoration: underline; }&lt;br /&gt;&lt;/style&gt;&lt;b&gt;Bug ID: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=2"&gt;2&lt;/a&gt;&lt;br /&gt;Short desc: &lt;a href="http://127.0.0.1/btnet/edit_bug.aspx?id=2"&gt;Object reference not set to an instance of an object.&lt;/a&gt;&lt;/b&gt; &lt;p&gt;&lt;table cellspacing="0" cellpadding="3" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Last changed by &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported By &lt;td&gt;FuncTest &lt;tr&gt;&lt;td&gt;Reported On &lt;td&gt;2008-01-31 10:25 &lt;tr&gt;&lt;td&gt;Project &lt;td&gt;Petshop Redux &lt;tr&gt;&lt;td&gt;Organization &lt;td&gt;Omega &lt;tr&gt;&lt;td&gt;Category &lt;td&gt;bug &lt;tr&gt;&lt;td&gt;Priority &lt;td&gt;high &lt;tr&gt;&lt;td&gt;Assigned &lt;td&gt;developer &lt;tr&gt;&lt;td&gt;Status &lt;td&gt;new &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;p&gt;&lt;table cellspacing="0" cellpadding="4" border="1"&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table id="posts_table" cellspacing="3" cellpadding="0" border="0"&gt;&lt;br /&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="cmt"&gt;&lt;table width="100%"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="left"&gt;&lt;span class="pst"&gt;comment &lt;a name="1"&gt;&lt;/a&gt;1 posted by FuncTest on 2008-01-31 10:25 &lt;/span&gt;&lt;/td&gt;&lt;/td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table border="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="cmt_text"&gt;Test case reference (#4578) ; Create Order with no products.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I get this strange message saying "Object reference not set to an instance of an object." But I have not made a reference to an order yet ??&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can you check this? Urgent, is blocking me.&lt;/span&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/table&gt;&lt;div class="align"&gt;&lt;table border="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Ok , you say : &lt;/p&gt;&lt;blockquote&gt;"The tester is doing a great job ! I'll quickly instruct the developers to fix&lt;br /&gt;these errors. "&lt;/blockquote&gt;&lt;p&gt;Or .... you could take a step back and analyze the type of bug the tester has found. You shoudl may be take a look at the test cases result of the tester . You might find out that the tester wasn't able to do a lot of testing after all because he was blocked by the bugs... &lt;/p&gt;&lt;p&gt;The Bug list (artifical) shows a high digree of programming errors . There are no real findings of missing functionality, wrongly interpreted specifiaction. In other words the function tester has been able to do his/her thing. The tester got hold up by types of errors that are more technical in nature. Now the functional tester is somehow blocked until the corrected version is released again in QA. Your project manager will not be happy to see his/her people being idle.&lt;/p&gt;&lt;p&gt;It's time to revise your development process , educate your developers and give them the means to conduct testing themselves : enter development testing and test automation.&lt;/p&gt;&lt;p&gt;Maybe your developers will answer : &lt;/p&gt;&lt;ul&gt;&lt;li&gt;What are you talking about, we already do testing! : Maybe that is true . For example making a Form with 23 buttons and text boxes that test some piece of code they have written. The trouble with this approach is that it a custom implementation. Each developer can do what he likes. It can not be (easily) automated : you must click on the buttons and verify the result in a file or through the textboxes.&lt;/li&gt;&lt;li&gt;We don't have time to do testing! : Yes testing is hard and does take time. But finding a bug early on is "cheaper" than when some poor tester finds it after a candidate release . Or even worse when the customer/end-user finds it. It will avoid long cycles of develop-test-correct-retest. When a developer finds a bug , he/she knows the context and can more easily hunt down the bug and eliminate it.&lt;/li&gt;&lt;li&gt;It is not our job , we have testers on the team. Why do it twice?: The developer testing is is somewhat different from functional testing (or non-functional testing like performance). In developer testing you primarly want to eliminate the any programming errors. Sure you have some clue how and end-user will use the application, but you're master of the code and therefore have more insight then, anyone where problems lure. So your entry point is the code itself . A functional tester looks at application from the outside (white-box vs. black-box). He doesn't see the code in motion. He only sees the interface of the system. The functional tester will concentrate more end-to-end scenario's that are possible (or that should not be possible) . Also testing throughout the process avoid big bang testing . When you test the smallest parts and continue testing by putting the tested parts together, the chance of (programming) errors coming up later in the process are reduced.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Introducing developer testing and preferably also test automation (for example Visual Stuid Test framwork or NUnit) is not soley a technical matter. You should get the developers to test that their code meets the "their" intentions . There will always be a loss infomation before a letter of code is typed. So system testing remains necessary . Developers should think about what can go wrong with what they're coding, as they're coding it or even before they start coding (TDD). Early detection of errors cost less in the construction phase. System / acceptance test never can reach same coverage of testing. Developers should control quality before shipping next phase (minor for example at check-in or major : release to QA) .&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Of course testing alone won't cut it. Testing does not put quality into the code. It just gives insight in the quality of the code (application). You will still need tons of other measures to assure quality code...But that's for another post.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-5668612008276680827?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/5668612008276680827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=5668612008276680827' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/5668612008276680827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/5668612008276680827'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/02/dont-bother-system-testers-with.html' title='Don’t bother System testers with programming errors.'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_GROsRPS-U-k/R7L4QGb7Q2I/AAAAAAAAAKc/PuBWw2VorQw/s72-c/bugtracker.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-6422842618668911282</id><published>2008-02-08T10:30:00.000+01:00</published><updated>2008-02-08T10:36:51.098+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio Extensibility'/><title type='text'>GAT : Skeleton Pattern</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;This entry describes another typical scenario where you can use GAT to automate certain VS Solution creation activities.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Driving forces&lt;br /&gt;&lt;/strong&gt;When developers in your organization want to create a new VS solution for an application , you want to help them in creating a typical structure of a multiple-project solution. You don’t want a describe everything in detail in a document but you want to automate as much as possible and make it available within the VS environment. You want also to add some possibility for customization of namespace and project naming.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solution&lt;br /&gt;&lt;/strong&gt;Use the GAT to make a Guidance package that unfolds the “Skeleton” structure. Add some recipe wizards to collect initial information from the user. Install the Guidance Package on the developers machine to make the Guidance Package available in Visual Studio 2008. The developer can choose the “skeleton” from the Visual Studio 2008 new project–dialog to unfold the initial structure of the solution after entering initial values to create the skeleton.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Structure&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5164540591371834178" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/R6wiThDN00I/AAAAAAAAAKU/iUeA85W4nAc/s400/GATSkeletonpattern.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Attention&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Guidance package ,GAT template for making Guidance Packages should be stripped to bare minimum before proceeding with own package creation&lt;/li&gt;&lt;li&gt;References to assemblies, must exist on target machine (GAC or same folder : Hintpath !!!)&lt;/li&gt;&lt;li&gt;Take care of parameter replacements ; In project files (references) and import statements in any code.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;&lt;strong&gt;Alternatives&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Copy-paste a skeleton available in a source control system&lt;/li&gt;&lt;li&gt;“Pure” VS2005 templates solution with parameter replacement and Wizard extension mechanism&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-6422842618668911282?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/6422842618668911282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=6422842618668911282' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6422842618668911282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6422842618668911282'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/02/gat-skeleton-pattern.html' title='GAT : Skeleton Pattern'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_GROsRPS-U-k/R6wiThDN00I/AAAAAAAAAKU/iUeA85W4nAc/s72-c/GATSkeletonpattern.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-473793295494038131</id><published>2008-02-07T08:23:00.000+01:00</published><updated>2008-02-08T10:37:23.946+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio Extensibility'/><title type='text'>GAT : StarterKit Pattern</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Making guidance packages GAT (Guidance Automation toolkit) is also making knowledge available for novice users regarding certain processes or technology. This entry I will discuss a typical scenario of how you can make an example application available through GAT in Visual Studio 2008.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Driving forces&lt;br /&gt;&lt;/strong&gt;You want to make a working example of how a typical Winforms application is made in your organization available for your developers. The developers must be able to run it , learn from it and make changes to it if they want to.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;br /&gt;Use the GAT to make a Guidance package that unfolds the “Starterkit” application. Install the Guidance Package on the developers machine to make the Guidance Package available in Visual Studio 2008. The developer can choose the Starterkit from the Visual Studio 2008 new project–dialog to create the example application.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;img id="BLOGGER_PHOTO_ID_5164137332597445426" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 422px; CURSOR: hand; HEIGHT: 325px; TEXT-ALIGN: center" height="343" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R6qzixDN0zI/AAAAAAAAAKM/0nTvdgCj6yI/s400/GATstarterkitPattern.JPG" width="443" border="0" /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Attention&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;GAT template for making Guidance Packages should be stripped to bare minimum before proceeding with own package creation&lt;/li&gt;&lt;li&gt;References to assemblies, must exist on target machine (GAC or same folder : Hintpath !!!)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Alternatives&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Installed example application a demo box&lt;/li&gt;&lt;li&gt;Example application in SourceSafe&lt;/li&gt;&lt;li&gt;Setup package (msi) of the application with all the sources&lt;/li&gt;&lt;li&gt;“Pure” VS2005 templates solution&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-473793295494038131?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/473793295494038131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=473793295494038131' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/473793295494038131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/473793295494038131'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/02/gat-starterkit-pattern.html' title='GAT : StarterKit Pattern'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/R6qzixDN0zI/AAAAAAAAAKM/0nTvdgCj6yI/s72-c/GATstarterkitPattern.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-5182472461195753497</id><published>2008-02-06T08:38:00.000+01:00</published><updated>2008-02-11T08:44:45.507+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio Extensibility'/><title type='text'>First steps with the Guidance Automation Toolkit (GAT)</title><content type='html'>Hello,&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;I recently tried out the &lt;strong&gt;Guidance Automation Toolkit &lt;/strong&gt;and its "run-time" companion &lt;strong&gt;Guidance Automation Extensions&lt;/strong&gt; (GAX/GAT - July 2007 CTP) on VS Rosario November CTP image. &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5163783848199050002" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/R6lyDRDN0xI/AAAAAAAAAJ8/d1uO1v97yvU/s400/GAT.JPG" border="0" /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;The GAT enables you to extent the Visual Studio 2005/2008 experience. Extensibility comes in different forms and shapes but the GAT is geared helping the developer when creating a VS solution. It gives "guidance" in the form VS project or item templates combined with automation hooks (recipes) that can collect information from the developer (wizards) while the solution structure is being created (un-folded).&lt;/div&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5163787473151447842" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/R6l1WRDN0yI/AAAAAAAAAKE/RywhRRp2Cjk/s400/GATusage.JPG" border="0" /&gt; &lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;GAT find it's origin in the Microsoft &lt;strong&gt;Software Factory Initiative&lt;/strong&gt;. The Software Factories provide you with a set of proven practices for building distributed applications. These practices are exposed through architectural overviews, patterns, how-to topics, reference implementations, automated guidance packages, and application blocks. There are several SW factories you can download today ( Web Service (WSF), Smart Client(SCSF), web client (WCSF))&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5163774906077139618" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/R6lp6xDN0qI/AAAAAAAAAJE/krV2Xf0dSow/s400/SF.JPG" border="0" /&gt; The idea behind GAT is not completely new. A previuos technology in VS2003, the &lt;strong&gt;Enterprise Templates &lt;/strong&gt;was also an effort for rapidly defining the initial structure of applications and to minimize the need to read through a bunch of of white papers, standards, and policies documents. &lt;img id="BLOGGER_PHOTO_ID_5163778638403719890" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R6ltUBDN0tI/AAAAAAAAAJc/-TgKWuFQ8L4/s400/EnterpriseTemplateLibary.JPG" border="0" /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5163776997726212802" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/R6lr0hDN0sI/AAAAAAAAAJU/gkBiCu8fA2Y/s400/EnterpriseTemplateLibary.bmp" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;In VS2005 we've got the new template mechanism (&lt;strong&gt;Visual Studio Templates&lt;/strong&gt;) . The Export template makes is fairly easy to make shareable templates. Actually GAT uses these exported template. What makes GAT different is the way you can hook automation to these templates.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5163775142300340914" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/R6lqIhDN0rI/AAAAAAAAAJM/XNcdnL8brCY/s400/ExportTemplate.JPG" border="0" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Wojtek Kozaczynski (&lt;a href="http://blogs.msdn.com/wojtek/archive/2005/05/02/414129.aspx"&gt;http://blogs.msdn.com/wojtek/archive/2005/05/02/414129.aspx&lt;/a&gt;) has a nice blog-entry describing the origins of GAT.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yet another technology, called &lt;strong&gt;Domain Specific Languages&lt;/strong&gt; (DSL), is available to extent VS. The DSL Toolkist (in the SDK) allows you to build visual interaction component that can be used from with in VS just like you would for example use a Winform Form designer. You drag &amp;amp; drop the visual elements on the form and code is generated for you. An example in the SDk is a DSL that enables you to visually build a Wizard-like application. So you get a special toolbar and drag &amp;amp; drop the visual elements on your "canvas" and "model" your wizard application. The model then is used by a code generator to produce executable code.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5163781155254555362" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/R6lvmhDN0uI/AAAAAAAAAJk/2v4D4rk-kJg/s400/DSL.bmp" border="0" /&gt; &lt;div&gt;So GAT and DSL Tools both build on top of existing VS extensibility featueres but with more possibility in guidance experience or modelling experience. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;Daniel Cazzulino has some thought about the status of developer guidance in realm of GAT, DSL and Software Factories (&lt;a href="http://www.clariusconsulting.net/blogs/kzu/archive/2007/01/08/BuildingSoftwareFactoriesToday.aspx"&gt;http://www.clariusconsulting.net/blogs/kzu/archive/2007/01/08/BuildingSoftwareFactoriesToday.aspx&lt;/a&gt;)&lt;br /&gt;&lt;/div&gt;&lt;p&gt;So I see certainly &lt;strong&gt;advantages&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Productivity can be increased : It includes automation for Visual Studio: with this automation, de-velopers can easily apply guidance in consistent and repeatable ways.&lt;/li&gt;&lt;li&gt;Adaptable : It is open and customizable.development leads can customize the factory to meet specific needs.&lt;/li&gt;&lt;li&gt;Accelerated start. It provides an effective way for architects and developers to create a high-quality starting point for their application. This means that projects begin with a greater level of maturity than applications developed from scratch.&lt;/li&gt;&lt;li&gt;Enforce standards : to enforce standards independent of the solution domain&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;But I have also some &lt;strong&gt;concerns&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Support : I don’t think so. Is not an official product of MS. It’s from the Patterens &amp;amp; practices group. It is still CTP ... since July 2005. Forum exists but I haven't seen any MS employee replying to questions...(&lt;a href="http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=78&amp;amp;SiteID=1"&gt;http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=78&amp;amp;SiteID=1&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Some (steep) learning curveExamples only on blogs (&lt;a href="http://jelle.druyts.net/CategoryView.aspx?category=Blog%7CProgramming%7C.NET%7CGuidanceAutomation"&gt;http://jelle.druyts.net/CategoryView.aspx?category=Blog%7CProgramming%7C.NET%7CGuidanceAutomation&lt;/a&gt;) or you have to dissect the WSF/SMSF/SCSF or you have to study the default Guidance package that is produced when you create a new guidance package project.&lt;/li&gt;&lt;li&gt;Support for next versions of GAT/GAX once an application has been built with a version of GAT/GAX &lt;/li&gt;&lt;li&gt;Mistakes are severely punished :-). You can easily scr*w up your registry (like I did)  without a warning. Re-installing GAX/GAT can result in something like this&lt;/li&gt;&lt;/ul&gt;&lt;img id="BLOGGER_PHOTO_ID_5163782542528992002" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/R6lw3RDN0wI/AAAAAAAAAJ0/hSmuXcP-6_k/s400/badGAT.JPG" border="0" /&gt; In that respect Victor Garcia Aprea from Clarius Consulting made a &lt;strong&gt;GaxTroubleshooter&lt;/strong&gt; (&lt;a href="http://weblogs.asp.net/vga/archive/2007/12/28/troubleshooting-gax-gat-installation-issues.aspx"&gt;http://weblogs.asp.net/vga/archive/2007/12/28/troubleshooting-gax-gat-installation-issues.aspx&lt;/a&gt;) but I wasn't able to repair my mistakes with it though. Clarius has also a&lt;strong&gt; Software Factory Toolkit&lt;/strong&gt; (&lt;a href="http://www.softwarefactoriestoolkit.net/"&gt;http://www.softwarefactoriestoolkit.net/&lt;/a&gt;) but I dare not to re-install it because it is rather invasive . It seems to intervene in the default GAX/GAT installation.&lt;br /&gt;&lt;br /&gt;Does someone actualy used al these specific VS features to create a custom Guidance package ? What were your experiences? Like to hear from you.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Best regards,&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Alexander&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-5182472461195753497?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/5182472461195753497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=5182472461195753497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/5182472461195753497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/5182472461195753497'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/02/first-steps-with-guidance-automation.html' title='First steps with the Guidance Automation Toolkit (GAT)'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_GROsRPS-U-k/R6lyDRDN0xI/AAAAAAAAAJ8/d1uO1v97yvU/s72-c/GAT.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-7789744392862004516</id><published>2008-01-22T10:16:00.000+01:00</published><updated>2008-01-22T11:00:41.380+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO Entity Framework'/><title type='text'>Unit testing ADO Entity Framework</title><content type='html'>Hello,&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;I was playing with the ADO.NET entity framework beta 3 that I installed on the Rosario November 2007 CTP and I had some problems making unit tests. I kept getting the follwing error.&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;System.Data.MetadataException: The specified metadata path is not valid. A valid&lt;br /&gt;path must be either an existing directory, an existing file with extension&lt;br /&gt;'.csdl', '.ssdl', or '.msl', or a URI that identifies an embedded resource &lt;/blockquote&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;When you use the wizard to create a model several "hidden" files are generated for you; .csdl, .ssdl, and .msl files. The information contained in these files is encapsulated in the .edmx file but the files .csdl, .ssdl, and .msl files reside in the bin\Debug or bin\Release directories of the solution. Apperently these files are still necessary at run-time. There not embedded in the assembly.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5158229835402049538" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 413px; CURSOR: hand; HEIGHT: 187px; TEXT-ALIGN: center" height="227" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R5W2tLD1-AI/AAAAAAAAAIU/Um91JQ21ywE/s400/vs2008UTEDM.bmp" width="449" border="0" /&gt; In a connectionstring you specify these files in the metadata part :&lt;/div&gt;&lt;div&gt;connectionString="&lt;strong&gt;metadata&lt;/strong&gt;=.\Northwind.csdl.\Northwind.ssdl.\Northwind.msl&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;p&gt;When you're using for example the VS test framework, the test infrastructure copies the assemblies to a certain test folder (isolation). If you have an app.config or use custom files in your code, you must assure that the test framework put these file in that particular test folder.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now the .csdl, .ssdl, and .msl are also not copied to that test folder automatically. I used the deployment feature of the VS test environment. I specified the three files and now there copied to the test folder.&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5158232567001249842" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R5W5MLD1-DI/AAAAAAAAAIs/wtlD3xJ2sOQ/s400/testrunconfig.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5158233915620980802" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/R5W6arD1-EI/AAAAAAAAAI0/3Lc6j2x3rtA/s400/testfolder.JPG" border="0" /&gt;&lt;br /&gt;&lt;p&gt;Maybe there are other ways? Let me know! &lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-7789744392862004516?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/7789744392862004516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=7789744392862004516' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/7789744392862004516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/7789744392862004516'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/01/unit-testing-ado-entity-framework.html' title='Unit testing ADO Entity Framework'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/R5W2tLD1-AI/AAAAAAAAAIU/Um91JQ21ywE/s72-c/vs2008UTEDM.bmp' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-1941796830887455830</id><published>2008-01-13T21:46:00.000+01:00</published><updated>2008-01-13T22:21:20.052+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><title type='text'>Unit Testing Checklist</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;Over time I compiled a list of things regarding unit and unit integration tests; books, articles, forums and other blogs. I did not always kept track where I found some piece of information. So I certainly don't take any credit in this list (except compiling it).  Recently I discovered the XUnit Test Patterns website by Gerad Meszaros (&lt;a href="http://xunitpatterns.com/index.html"&gt;http://xunitpatterns.com/index.html&lt;/a&gt;).  I wished I found that one earlier.&lt;br /&gt;&lt;br /&gt;Still I wanted to share with you the following list.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Do you know how to incorporate the unit testing into the development process?&lt;br /&gt;Unit tests are written by the developer who write the code and executed by the developer.&lt;br /&gt;Feedback period between coding and finding error is smaller&lt;br /&gt;Coder and tester is same person&lt;br /&gt;Accounted in the development budget&lt;br /&gt;Continuous testing versus phase-end testing&lt;br /&gt;Avoid arguments like: I don’t have the time to conduct unit test. I must deliver ASAP.&lt;br /&gt;Don’t rely on phase-end tests to find your errors.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you have a strategy to incorporate unit test code in production code organization?&lt;br /&gt;Be prepared to see as much production code as test code so good organization primordial.&lt;br /&gt;Integration in source control system is needed&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Are you aware of the type of errors unit testing tries to find?&lt;br /&gt;Some errors are easier to find with unit (integration) test than in formal phase-end tests. Or at least the effort is bigger to find those errors.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you use an automated tool such as NUnit or VS2005 Integrated testing Framework to make the unit-testing process easy and repeatable?&lt;br /&gt;Same Framework available for every developer. Same framework used by every developer.&lt;br /&gt;Automation in two ways: invoking the tests and checking the results.&lt;br /&gt;Can be integrated into automatic build/continuous integration scheme.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you know which type (layer) of code benefits the most of unit testing?&lt;br /&gt;Some type code is more appropriate for unit testing than other for example business logic versus User interface.&lt;br /&gt;Whenever you are tempted to write something into a debug.writeLine type of thing, write a test for it&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you know how to deal with code that is to hard to unit test?&lt;br /&gt;Consider other ways of testing&lt;br /&gt;GUI skin code,Main methods ,Asynchronous method ,mult-threading&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you know how to deal with developers that don’t write unit code?&lt;br /&gt;Education&lt;br /&gt;Take away resistance by showing advantages&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you how to avoid that unit-testing becomes de-prioritized when deadlines come near?&lt;br /&gt;Planning&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you have the right mindset to conduct unit test?&lt;br /&gt;Showing that it works versus finding errors versus&lt;br /&gt;verifying expectations (specification) compared to the realisation (code)&lt;br /&gt;Are you prepared to scrutinize your work?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you know when to write unit test?&lt;br /&gt;Write the tests as you go along. Don’t leave them for a “later” that may never come.&lt;br /&gt;Do you know when to execute unit test?&lt;br /&gt;Run unit test as often as possible to decrease feedback period between coding and finding error is smaller&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Do you know how to integrate unit testing into the build process /continuous integration scheme?&lt;br /&gt;Unattended execution of unit tests to let the test run as much as possible.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you have a policy about how to deal with failed unit test?&lt;br /&gt;Make sure code passes unit tests and integration tests before you check it into the source control system.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you make a distinction between pure unit test and unit integration test and when to use the them?&lt;br /&gt;Make test for collaborating units in function in stead of big bang approach in system testing. Unit test are good for regression testing&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you have a policy to distribute knowledge about conduction unit testing and unit (integration) testing and automated testing in general?&lt;br /&gt;Optimal use of resources&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you have a policy to use unit test for regression testing?&lt;br /&gt;Changes to an existing product may not result in breaking unit tests.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you have a policy to keep the quality of unit tests high?&lt;br /&gt;Avoid that the first unit test are good and the remaining unit test are of lesser quality (Coverage) because of time pressure.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you consider the unit test code on the same level as production code?&lt;br /&gt;Be prepared to see as much production code as test code.&lt;br /&gt;Test must be written and maintained to the same professional standards as your production code&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you code to Interfaces rather than Classes?&lt;br /&gt;To plug in different implementations at runtime or test time.&lt;br /&gt;Makes it easy to provide test stubs that don’t need a sophisticated implementation of collaborators’ functionality and hence are freed from needing to depend on supporting infrastructure.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you use Inversion of Control/dependency injection pattern?&lt;br /&gt;Makes is easier to feed the class under test with alternative implementations of collaborating classes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Does each class have a well-defined set of responsibilities?&lt;br /&gt;So it will be more easy to come up with unit test.&lt;br /&gt;High cohesion , low coupling&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you expose too much of a class for the sake of testability?&lt;br /&gt;Don’t mark a method public just for the sake of testability. Keep encapsulation in mind.&lt;br /&gt;VS2005 test framework can deal with class and methods marked friend or private.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you separate unit test code from the code under test?&lt;br /&gt;Unnecessary code to deploy.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Is there one test class per class under test?&lt;br /&gt;Code generation of VS2005 test framework encourages it and uses it when you generate additional test method skeletons&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Is there a separate assembly per assembly under test?&lt;br /&gt;Code generation of VS2005 test framework encourages it and uses it when you generate additional test class skeletons&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Is there a separation between tests that need configuration files and the one that don’t need configuration files?&lt;br /&gt;You can more easily identify which test should be able to run on any machine without setup (eg. Build server)&lt;br /&gt;Pay attention on place of test data /configuration files because of the way xUnit framework works.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Is there a separation pure unit test and unit integration test?&lt;br /&gt;With unit integration test you must always verify if the collaborating units didn’t cause an error when a test should fail.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you separate database access code test?&lt;br /&gt;This kind of tests requires much more attention in preparation, configuration and execution speed.&lt;br /&gt;Is  the unit testing code under source control&lt;br /&gt;Is part of the code base.&lt;br /&gt;Any developer must be able to use it afterwards.&lt;br /&gt;An automatic system (Build/CI) must be able to use it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Can all test methods run autonomous so they don’t rely on other test or require that they are run in a particular order?&lt;br /&gt;Test method can be selected/de-selected via the Test UI so test must run independent of each other.&lt;br /&gt;VS2005 test framework allows ordered test runs (more functional like testing, use case scripts)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Is every test able to run over and over again, in any order, and produce the same results?&lt;br /&gt;Otherwise automation of the assertions is difficult.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you use mocks or stubs to accomplish test repeatability?&lt;br /&gt;Use mock objects /stubs help you to isolate the item under test and keep it independent from the environment because they give always the expected values.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider positive unit tests?&lt;br /&gt;To exercise the code as intended and verify the right result.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider negative unit tests?&lt;br /&gt;To intentionally misuse the code and verify for robustness and appropriate error handling.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider "Stress" tests?&lt;br /&gt;To check the code for its limits (overflow , etc).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider data conformance test?&lt;br /&gt;To check whether an result value conforms to an expected format&lt;br /&gt;To check how  the code deals with input value that conforms with expected data format and vice versa&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider Ordering tests?&lt;br /&gt;To check whether the set of result values are ordered or unordered as appropriate.&lt;br /&gt;To check how the code deals with input values that are ordered or unordered.&lt;br /&gt;Did you consider range tests?&lt;br /&gt;To check whether the result  falls within reasonable minimum and maximum values&lt;br /&gt;To check how the code deals with input values that fall within reasonable minimum and maximum values.&lt;br /&gt;To check how the code deals with input values that fall outside the boundaries of reasonable minimum and maximum values.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider reference tests?&lt;br /&gt;At the end of the method, post conditions are those things that you guarantee your method will make happen. Direct results returned by the method are one obvious thing to check, but if the method has any side-effects then you need to check those as well.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider existence tests?&lt;br /&gt;To test whether the result exist (e.g., is non-null, non- zero, present in a set, etc.)?&lt;br /&gt;To test how the code deals with empty or missing input values (such as 0, 0.0, “”, or null).&lt;br /&gt;Did you consider cardinality tests?&lt;br /&gt;To test whether there are there exactly enough values in the result.&lt;br /&gt;To see how the code deals with input value list that is of the correct size or contains duplicates.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider process logic test?&lt;br /&gt;To check if all control structure constructs (if, else, case, etc.) function correctly.&lt;br /&gt;Did you consider which part of the code is reasonable for testing invalid parameters?&lt;br /&gt;Check input at the boundaries of the system, and you won't have to duplicate those tests inside the system. Internal components can trust that if the data has made it this far into the system, then it must be okay. You still can take the pessimistic way but then be prepared to see a lot of extra unit tests.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you use code coverage tools?&lt;br /&gt;In order to verify the thoroughness of the unit tests&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you write tests for bug-fixes?&lt;br /&gt;To demonstrate the bug isn’t present anymore.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do you test for specific number/datetime problems like rounding’s , regional settings?&lt;br /&gt;Decimal sign, DD/MM/YYY versus MM/DD/YYYY&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Does the unit test method only test one specific thing?&lt;br /&gt;When a unit test breaks you can more easily pinpoint the problem. Maybe even without debugging.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider the use of a Mock library or a stub while unit integration testing?&lt;br /&gt;A stub is a piece of code used to stand in for some other programming functionality. A stub may simulate the behaviour of existing code (such as a procedure on a remote machine) or be a temporary substitute for yet-to-be-developed code. Stubs are therefore useful in unit testing.&lt;br /&gt;Mock objects are simulated objects that mimic the behaviour of real objects in controlled ways. In a unit test, mock objects can simulate the behaviour of complex, real (non-mock) objects and are therefore useful when a real object is difficult or impossible to incorporate into a unit test.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Are the test suites enough self-documenting?&lt;br /&gt;Documentation in the form of meaningful test case names and assertion messages is usually more important than comments on test cases itself. When a test fails, the output will show the failed assertion (or an error) and the name of the test in question&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Is the name of the test method intention-revealing?&lt;br /&gt;Name unit test shows up in interactive screen reports and console output&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you avoid test method names with an appended numbers to distinct between them?&lt;br /&gt;That doesn’t do a very good job of communicating your intentions&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Is there a consistent naming convention for the unit test code?&lt;br /&gt;So you know what are the test methods and the help methods.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider putting setup code that is used in every test method put into separate initialization XUnit framework methods that are triggered on test class or test method level?&lt;br /&gt;Excessive data setup can obfuscate a unit test beyond comprehension so hide it if needed.&lt;br /&gt;All state is known in advance and will always be the same no matter where or when your test is run.&lt;br /&gt;To avoid one unit test leaves some kind of dirty data hanging around&lt;br /&gt;Preconditions that must be true when you want to run the method under test.&lt;br /&gt; &lt;/li&gt;&lt;li&gt;Is your unit test fast?&lt;br /&gt;Many unit tests are launched often so fast execution avoids friction and encourages you to run them often.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider factory methods that create the object instance under test for you?&lt;br /&gt;You can then reuse that method to get fresh instances of your class under test in other test methods. This helps to keep the tests maintainable across time and guards your tests from unforeseen changes to the code under test.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Is the actual act of executing the method under test separated from the act of asserting on the result by creating a result variable on a different line?&lt;br /&gt;The invocation against the object under test may be very long and might make your Assert line stretch all the way beyond the edge of the screen, forcing the test reader to scroll to the right.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Does the variable that contains the result have a readable name?&lt;br /&gt;Makes your Assert line very understandable and easy to read&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you consider using separate verification methods?&lt;br /&gt;This is a reusable method in your test class that contains an Assert statement but that can take different inputs and verify something on them.&lt;br /&gt;You can use these verification methods when you are asserting the same thing over and over again with varying inputs.&lt;br /&gt;Even though the Assert is located in a different method, if the Assert fails you'll still get an assert exception and the original calling test will be shown in the test failure output window.&lt;br /&gt;Can improve readability.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you avoid multiple Asserts in a Single Unit Test?&lt;br /&gt;After a failure, subsequent Asserts aren't executed.&lt;br /&gt;These unused Asserts could provide valuable data (or symptoms) that would help you quickly narrow your focus and discover the underlying problem.&lt;br /&gt;Put the additional Asserts should be run in separate, self-contained unit tests so that you have a good opportunity to see what fails.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Did you use an informative assert message?&lt;br /&gt;A good Assert message should always explain either what should have happened or what happened and why it's wrong. shows up in interactive screen reports and console output&lt;br /&gt;Test code maintenance&lt;br /&gt; &lt;/li&gt;&lt;li&gt;Did you avoid code duplication?&lt;br /&gt;Refactor the Test Suite as necessary and identify areas in which you can reuse code to speed up writing individual test cases&lt;br /&gt;&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a name="_Toc177443427"&gt;&lt;/a&gt;References &amp;amp; recommend reading&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;xUnit Test Patterns: Refactoring Test Code, Gerard Meszaros, 2007 by Addison Wesley Professional&lt;/li&gt;&lt;li&gt;The Art of Unit Testing, Roy Osherove, Manning 2008 (MEAP 2007)&lt;/li&gt;&lt;li&gt;Next Generation Java Testing: TestNG and Advanced Concepts ,Cédric Beust and Hani Suleiman, Addison-Wesley 2007&lt;/li&gt;&lt;li&gt;Pragmatic Unit Testing in Java with JUnit ,Andy Hunt and Dave Thomas  ,Pragmatic Programmers LLC  2004&lt;/li&gt;&lt;li&gt;Pragmatic Unit Testing in C# with NUnit: The Pragmatic Starter Kit, Volume II ,Andy Hunt and Dave Thomas , Pragmatic Programmers LLC © 2004&lt;/li&gt;&lt;li&gt;Coder to Developer: Tools and Strategies for Delivering Your Software ,Mike Gunderloy  ,Sybex 2004&lt;/li&gt;&lt;li&gt;EJB Design Patterns ,Floyd Marinescu  John Wiley &amp;amp; Sons 2002&lt;/li&gt;&lt;li&gt;Code Craft: The Practice of Writing Excellent Code ,Pete Goodliffe  No Starch Press 2007&lt;/li&gt;&lt;li&gt;Code Complete, Second Edition ,Steve McConnell  ,Microsoft Press 2004&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Alexander&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-1941796830887455830?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/1941796830887455830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=1941796830887455830' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1941796830887455830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1941796830887455830'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2008/01/unit-testing-checklist.html' title='Unit Testing Checklist'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-611793692729239566</id><published>2007-12-20T09:05:00.000+01:00</published><updated>2007-12-20T10:33:58.367+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio Team System'/><title type='text'>MSDN session Application Lifecycle Management with Visual Studio Team System (19/12/2007)</title><content type='html'>Hello,&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Yesterday I attended the MSDN evening session about Application Life cycle Management (ALM) with Visual Studio Team System (VSTS). &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;It was very interesting and very well presented by Yves Goeleven (Compuware Belgium). He was very knowledgeable about the subject and VSTS in particular. His presentation was a good mix between slides and demo's so you had a good feel what actually was meant.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Still I have some "concerns" about the subject. Concerns are formulated as "I wish I knew how to ...."&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Position VSTS/TFS as an ALM tool or more as an SDLC tool? Yes there are hooks (extensibility)....&lt;/li&gt;&lt;li&gt;Capture the requirements from the customer in VSTS? And manage them in VSTS? Yes a wokitem will be the "materialization" of a requirement. But is this still the language of the customer? &lt;/li&gt;&lt;li&gt;To model use case diagrams, UML class diagrams , User stories&lt;/li&gt;&lt;li&gt;To integrate with operations (deployment, monitoring, incidents , capacity management)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;I looked up the the terms ALM and SDLC. Application Lifecycle Management (ALM) is the administration and control of an application from inception to its demise. It embraces requirements management, system design, software development , testing , configuration management and operating the information system. The following picture tries to capture that idea.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;img id="BLOGGER_PHOTO_ID_5145968196204199026" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R2omz1g1fHI/AAAAAAAAAIE/dzzpo0pJxII/s400/ALM.bmp" border="0" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Key is that the life of application does not start at the beginning of development. It start somewhere in the “business”. The end of application is not when it is delivered or even installed. It must be kept up and running to serve the business. It is also called life cycle because in effect an “application” is never finished. It is not something like a tangible product that rolls out a factory. It’s an ongoing process where new insights and requirements shape the life of an application, hence application life cycle management. As the business changes, information requirements change, and the cycle continues. Sometimes resulting in the demise of an existing system and the birth of a new application.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;The software development Lifecycle (SDLC) on the other hand has everything to do with developing the information system. But it gets kicked of by the business and hands over application to operations. It is also a lifecycle because within one ALM cycle because it is the rare exception that everything is said from the beginning. So there can be several iterations before an applications gets to be delivered to the business. On the other hand of course a change request or new requirements can trigger of a new ALM cycle.&lt;br /&gt;&lt;br /&gt;In order to achieve business objectives within an organization via information systems, user functional and non functional requirements must be defined in a consistent manner, prioritized and monitored. The administration and control of the information needs of users (Requirement Management) is therefore primary motor in the ALM and de facto also in the SDLC. All the “knowledge” that’s is necessary to transform these requirements into an information system is produced during the SDLC and put into a repository (or a collection of repositories). This will for the test basis for the test cases that will be used to verify it the information does what needs to do.&lt;br /&gt;The SDLC will take that the requirement will be turned into architecture and design specifications which will eventually lead into code doing what the business expects it to do. Herein lies the objective of testing. Testing actually is conducted throughout the SDLC. Testing preparation can even start as soon as the requirements are written down (testable requirements concept). During development in the form of unit and unit integration testing or system testing (functional, security , performance ,etc). Before the application get rolled-out, the business itself can conduct test in the form of user (functional) acceptance test. Also operations can conducts acceptance tests that verify the operational requirements.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;The input for establishing these test case are the expectations of the business. Ideally written down in the form of requirement, detailed functional specification and design documents. So there is a strong link between all the knowledge of what the system must do and all the information of how system is going to be tested. &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;A integrated system (or an integrated set of tools) should bring some added value to manage this link. Because the objective of testing is to report if the system does what it needs to do. So traceability is a key feature of this tool. Other benefits are accountability (who did what when), visibility (what did we do so far). &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;So if we would define testing as a kind of “fit-for-purpose” activity, testing is another gatekeeper in the life cycle. With the results of testing the stakeholders (customer/project lead) can take a decision based on facts if there will be release or not (ALM cycle) or within the SDLC cycle if something has to be corrected before release. &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Monitoring the information system in production and the actual usage of the application will further keep the ALM cycle running by incident reporting (functional and non-functional).&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;So were does VSTS/TFS fit in this story?&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;I tried use the following picture to get some (visual) answers.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5145976257857813634" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/R2ouJFg1fII/AAAAAAAAAIM/ADvN4e7tjnI/s400/SDLC.bmp" border="0" /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;I can see several aspects being covered by VSTS while others (at this time) seem to not be (immediately) clear to me. Maybe this will change over time as learn more about ALM and VSTS/TFS in particular? I would be glad to hear your insights on the subject.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Best regards,&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Alexander&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-611793692729239566?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/611793692729239566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=611793692729239566' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/611793692729239566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/611793692729239566'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/12/msdn-session-application-lifecycle.html' title='MSDN session Application Lifecycle Management with Visual Studio Team System (19/12/2007)'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/R2omz1g1fHI/AAAAAAAAAIE/dzzpo0pJxII/s72-c/ALM.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-92733298341111421</id><published>2007-12-05T12:00:00.000+01:00</published><updated>2007-12-05T13:49:03.257+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Reporting Services'/><title type='text'>Trigger TimedSubscription programmatically</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;Subscriptions are a way to kickstart Reporting Service in delivering a report to somewhere instead of you asking for the report through a URL access request (portal or custom app). This is also callled push versus pull.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;You can configere a timed event to trigger off those kind of subscriptions. But in some occasions you want some "custom" event to trigger of a subscription. You can not configure something like that through the configuration tools (reportmanger or SqlServer Management Studio).&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Lukasz Pawlowski (&lt;a href="http://blogs.msdn.com/lukaszp/archive/2005/10/07/478391.aspx"&gt;http://blogs.msdn.com/lukaszp/archive/2005/10/07/478391.aspx&lt;/a&gt;) explained a way to tell Reporting Services to kick of a subscription with the SOAP API of Reporting Services. There is a method called FireEvent that can trigger the subscription. Lukasz suggests creating a dummy schedule that is will never run because it's configured in the passed. The report subscription you want to launch uses this dummy schedule. In a program you call the Firevent method on the reporting WebService .... and your report is delivered as you specifed it in your subscription. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;I will show some screenshots how I did it, following Lukasz's tips.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So this is the report I want to be delivered on a file share in PDF.&lt;/div&gt;&lt;p&gt;&lt;img id="BLOGGER_PHOTO_ID_5140448250175273314" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/R1aKcsH5uWI/AAAAAAAAAG0/41qWJqS58AY/s400/ReportExample.bmp" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;First I make a dummy shared schedule. But one that will never fire a time event.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img id="BLOGGER_PHOTO_ID_5140448679672002930" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/R1aK1sH5uXI/AAAAAAAAAG8/z2EAy-0I1Bw/s400/SharedSchedule.bmp" border="0" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div&gt;Now I create a new subscription on the report I showed before. It will use the shared schedule as Time Event generator.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;img id="BLOGGER_PHOTO_ID_5140450071241406866" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/R1aMGsH5uZI/AAAAAAAAAHM/DNQ3bEyWfDI/s400/NewReportSubScriptionSchedule.bmp" border="0" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;In order to launch this subscription I must simulate a time event. The SOAP API of Reporting Services just gives me that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5140455946756667826" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/R1aRcsH5ubI/AAAAAAAAAHc/W3WjJDxcUkU/s400/RSSOAPPAPI.bmp" border="0" /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;This is a code snippet in VB.NET 2005 of how you could just do that.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;img id="BLOGGER_PHOTO_ID_5140461263926180290" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/R1aWSMH5ucI/AAAAAAAAAHk/u1rYkFD80nI/s400/vb2005snippet.bmp" border="0" /&gt;It is important that you use the ID (ie. GUID) to specify the subscription. You can also look it up in the Subscription table of the reportserver database.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;img id="BLOGGER_PHOTO_ID_5140467032067258850" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R1abh8H5ueI/AAAAAAAAAH0/JBiFLljF_e4/s400/TableSubscriptions.bmp" border="0" /&gt;&lt;br /&gt;But before you go off and launch this code one thing is left to be configured (besides the folder share of course) . The account under which this program must execute will need "generate event" privilege on Reporting Service level. Because this is a single machine demo setup (november 07 CTP of Rosario). The user tfssetup is also as system admin on RS. So i just checked the checkbox for generating events on the RS syst. admin role .&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;img id="BLOGGER_PHOTO_ID_5140462359142840786" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R1aXR8H5udI/AAAAAAAAAHs/KFCGA6fT5vU/s400/GenerateEventPrivilige.bmp" border="0" /&gt;&lt;br /&gt;The code snippet you just so will actually write an entry in the reportserver.Event table. The RS service will pick it up and act upon it. In our example it will write a pdf file into the file share folder (on the local disk ).&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5140467306945165810" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R1abx8H5ufI/AAAAAAAAAH8/CWRUpHIDSJw/s400/TableEvent.bmp" border="0" /&gt;&lt;br /&gt;Have fun.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Best regards,&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Alexander&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-92733298341111421?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/92733298341111421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=92733298341111421' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/92733298341111421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/92733298341111421'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/12/trigger-timedsubscription.html' title='Trigger TimedSubscription programmatically'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_GROsRPS-U-k/R1aKcsH5uWI/AAAAAAAAAG0/41qWJqS58AY/s72-c/ReportExample.bmp' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-1374739384054357968</id><published>2007-12-04T08:28:00.000+01:00</published><updated>2007-12-04T08:57:35.320+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Navigation button Visual Studio 2005</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;When you open a freshly installed Visual Studio 2005 , you might miss certain things. For example the navigate backwards and forward button. Very handy when you navigate throughout your code.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can easily add those buttons but nevertheless it is a bit strange that are not included by default (at least not on my machine) In VS 2008 (at least in the Rosario November edition) they are present and even a litlle bit smarter too. You can choose where you want to go back.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Open the "tools" menu and go to the "customize" menu-item.In the "view" category you will find the two missing buttons. When you select them , you can drag-and-drop them on your toolbar.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img id="BLOGGER_PHOTO_ID_5140018323948943666" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/R1UDbsH5uTI/AAAAAAAAAGc/dV2DfQWXqoE/s400/CustomizeWindow.JPG" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img id="BLOGGER_PHOTO_ID_5140021648253630786" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R1UGdMH5uUI/AAAAAAAAAGk/RELuwZLzRqU/s400/NavigateionButtonsVs2005.JPG" border="0" /&gt;In Visual Studio 2008 you get the navigation buttons by default at a little bit more!&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;img id="BLOGGER_PHOTO_ID_5140022679045781842" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/R1UHZMH5uVI/AAAAAAAAAGs/Hczb1DJ6SUM/s400/NavigationButtonsVs2008.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Alexander&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-1374739384054357968?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/1374739384054357968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=1374739384054357968' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1374739384054357968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1374739384054357968'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/12/navigation-button-visual-studio-2005.html' title='Navigation button Visual Studio 2005'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_GROsRPS-U-k/R1UDbsH5uTI/AAAAAAAAAGc/dV2DfQWXqoE/s72-c/CustomizeWindow.JPG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-4190265361159237007</id><published>2007-11-16T12:41:00.000+01:00</published><updated>2007-11-16T13:28:36.241+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET Coding'/><title type='text'>Refactor!™ for Visual Basic® .NET 2008 and 2005</title><content type='html'>Hello, &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;In VS 2005 you have a refactor possibility in C# but there was none out-of-the-box in VB.NET. In VS 2008 it is still the same (at least in the Beta edition) for VB.NET. You still have to reside to third party products. Something odd to me because I would think that they would have had plenty of time to see how their C# colleagues did it . I guess they give the Visual Studio Eco system some crumbles from the table ...&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;DevExpress offers a FREE refactor product for Visual Studio. There was already a free version for VS2005. Now they have updated their refactor utility for VS2008. But the good news is that you also can use it in VS 2005. Moreover by registering, you are entitled to download and use a set of bonus refactorings for Visual Basic .NET including:&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Create Method Contract &lt;/li&gt;&lt;li&gt;String Composition to String.Format &lt;/li&gt;&lt;li&gt;Rename Local &lt;/li&gt;&lt;li&gt;Safe Rename &lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Check out their web-site (&lt;a href="http://www.devexpress.com/Products/NET/IDETools/VBRefactor/"&gt;http://www.devexpress.com/Products/NET/IDETools/VBRefactor/&lt;/a&gt;) for a complete overview of the refactors the add-on offers.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;The latest incarnation is called Refactor! Free VB.NET with Bonus Refactorings v2.5.8 release 11 october 2007&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Standard Version for Visual Studio 2005, 2008 (size 20,197,328 bytes)&lt;/li&gt;&lt;li&gt;Bonus Refactorings for Visual Studio 2005, 2008 (size 222,550 bytes) Only after registration.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;An example of a refactor form the bonus pack : String.Format. Very handy!&lt;/div&gt;&lt;div&gt;Here some screenshots while executing the String.Format refactor&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;img id="BLOGGER_PHOTO_ID_5133409598366911314" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/Rz2I1O09i1I/AAAAAAAAAGE/vHviOO2kA-Q/s400/RefactorStringFormatBefore.JPG" border="0" /&gt; &lt;img id="BLOGGER_PHOTO_ID_5133409752985733986" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/Rz2I-O09i2I/AAAAAAAAAGM/0sK7-Cz7IF8/s400/RefactorStringFormatExec.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5133410100878084978" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_GROsRPS-U-k/Rz2JSe09i3I/AAAAAAAAAGU/wQEY08YbQ0c/s400/RefactorStringFormatAfter.JPG" border="0" /&gt;Regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-4190265361159237007?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/4190265361159237007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=4190265361159237007' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/4190265361159237007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/4190265361159237007'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/11/refactor-for-visual-basic-net-2008-and.html' title='Refactor!™ for Visual Basic® .NET 2008 and 2005'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/Rz2I1O09i1I/AAAAAAAAAGE/vHviOO2kA-Q/s72-c/RefactorStringFormatBefore.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-2316539418402812565</id><published>2007-10-22T10:35:00.000+02:00</published><updated>2007-10-23T08:54:52.242+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><title type='text'>RDB Transactions [HYC00]</title><content type='html'>&lt;div align="left"&gt;Today I got an error message when I tried to connect to an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;RDB&lt;/span&gt; data server through the ADO.NET &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;ODBC&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;brigde&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;surrounded&lt;/span&gt; in a System.transaction. I'm using the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;ODBC&lt;/span&gt; driver for Oracle 3.02&lt;br /&gt;&lt;br /&gt;So the following piece of code gives an error&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;tx&lt;/span&gt; As New &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;TransactionScope&lt;/span&gt;&lt;br /&gt;           Using con As New &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;Odbc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;OdbcConnection&lt;/span&gt;&lt;br /&gt;                       con.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;ConnectionString&lt;/span&gt; = "Driver={Oracle &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;RDB&lt;/span&gt; Driver};server= ......"&lt;br /&gt;                       con.Open()&lt;br /&gt;                      ' do your work here&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;                      tx&lt;/span&gt;.Complete()&lt;br /&gt;             End Using&lt;br /&gt;End Using&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The following error is thrown : System.Data.Odbc.OdbcException: ERROR [&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;HYC&lt;/span&gt;00] [Oracle][&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;ODBC&lt;/span&gt;]Optional feature not implemented. Meaning that the driver does not support the version of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;ODBC&lt;/span&gt; behavior that the application requested.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;but when i slightly change the code, it works fine&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Using con As New &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;Odbc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;OdbcConnection&lt;/span&gt;&lt;br /&gt;con.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;ConnectionString&lt;/span&gt; = "Driver={Oracle &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;RDB&lt;/span&gt; Driver};server= ......"&lt;br /&gt;con.Open()&lt;br /&gt;Using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;tx&lt;/span&gt; As New &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;TransactionScope&lt;/span&gt;&lt;br /&gt;' do your work here&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;tx&lt;/span&gt;.Complete()&lt;br /&gt;End Using&lt;br /&gt;End Using &lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Also using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;ODBCTransaction&lt;/span&gt; Object works fine&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Dim &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;tx&lt;/span&gt; As &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;Odbc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;OdbcTransaction&lt;/span&gt; = Nothing&lt;br /&gt;Dim con As System.Data.Odbc.OdbcConnection = Nothing&lt;br /&gt;Try&lt;br /&gt;con = New System.Data.Odbc.OdbcConnection&lt;br /&gt;con.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;ConnectionString&lt;/span&gt; = "Driver={Oracle RDB Driver};server= ......"&lt;br /&gt;con.Open()&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;tx&lt;/span&gt; = con.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;BeginTransaction&lt;/span&gt;&lt;br /&gt;'do your work here&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;tx&lt;/span&gt;.Commit()&lt;br /&gt;Catch ex As Exception&lt;br /&gt;If &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;tx&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;IsNot&lt;/span&gt; Nothing Then &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;tx&lt;/span&gt;.Rollback()&lt;br /&gt;Throw&lt;br /&gt;Finally&lt;br /&gt;If &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;tx&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;IsNot&lt;/span&gt; Nothing Then &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;tx&lt;/span&gt;.Dispose()&lt;br /&gt;If con &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_36"&gt;IsNot&lt;/span&gt; Nothing Then con.Dispose()&lt;br /&gt;End Try&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So morale of the story ... somewhere System.transactions uses &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_37"&gt;ODBCtransactions&lt;/span&gt; ?&lt;br /&gt;&lt;br /&gt;Any info is welcome!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Regards,&lt;br /&gt;&lt;br /&gt;Alexander&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-2316539418402812565?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/2316539418402812565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=2316539418402812565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/2316539418402812565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/2316539418402812565'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/rdb-transactions-hyc00.html' title='RDB Transactions [HYC00]'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-1396383914108023580</id><published>2007-10-19T08:07:00.000+02:00</published><updated>2007-10-19T13:07:02.946+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET design'/><title type='text'>VISUG-devmatch 18/10/2007 - Datasets vs. OO</title><content type='html'>During this evening event , the Belgian Visual Studio user group (&lt;a href="http://www.visug.be/"&gt;http://www.visug.be/&lt;/a&gt;) invited two speaker to present their views regarding &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;datasets&lt;/span&gt;&lt;/span&gt;-&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;oriented&lt;/span&gt; development and a more object-oriented way of working respectively.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Kurt &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Claeys&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Ordina&lt;/span&gt;) was the advocate for the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;dataset&lt;/span&gt; approach while Yves &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Goeleven&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Compuware&lt;/span&gt;) "preached" the Domain-Driven Design(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;DDD&lt;/span&gt;) way. Both did a good job !&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Benefits (What did I learn)&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Use &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;dataset&lt;/span&gt;-approach in application &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;that &lt;/span&gt;needs to be build fast.&lt;/li&gt;&lt;li&gt;Use &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;dataset&lt;/span&gt;-approach If you are &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_10"&gt;more&lt;/span&gt; at ease with the relational model than &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;OO&lt;/span&gt;-models.&lt;/li&gt;&lt;li&gt;Use a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;dataset&lt;/span&gt; to persist information on a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;PDA&lt;/span&gt; . You can use the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;dataset&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;xml&lt;/span&gt; features for that.&lt;/li&gt;&lt;li&gt;Check out the new &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;dataset&lt;/span&gt; features in VS2008 . You can &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_17"&gt;separate&lt;/span&gt; the generated &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;TableAdapters&lt;/span&gt; from the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;dataset&lt;/span&gt; type in different projects. So you make a assembly with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;dataset&lt;/span&gt; types that are shared on several layers and/or tiers. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;There&lt;/span&gt; is also a "manager" that handles multi-table updates.&lt;/li&gt;&lt;li&gt;Microsoft continues to invest in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;Datasets&lt;/span&gt; (VS2008 , &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;LINQ&lt;/span&gt; to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;Datasets&lt;/span&gt;).&lt;/li&gt;&lt;li&gt;But Microsoft also tries to &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_25"&gt;keep&lt;/span&gt; up with the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;DDD&lt;/span&gt; camp (Entity Framework)&lt;/li&gt;&lt;li&gt;There is also stuff in between &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;LINQ to SQL&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Domain-driven design(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;DDD&lt;/span&gt;) is object-oriented design with emphasis on the problem domain. The domain model is the basis. I should catch up on that (&lt;a href="http://www.domaindrivendesign.com/"&gt;http://www.domaindrivendesign.com/&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;DDD&lt;/span&gt; is difficult. Expect big learning curve.&lt;/li&gt;&lt;li&gt;Don't expose domain layer immediately to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;UserInterface&lt;/span&gt; layer. You should consider other objects to transport the information of an entity (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;DDD&lt;/span&gt; for principal domain object representing &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_32"&gt;something&lt;/span&gt; valuable for the business (&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_33"&gt;customer&lt;/span&gt; order, etc).&lt;/li&gt;&lt;li&gt;Use an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;ORM&lt;/span&gt; to help you bridge the Object-Relational mismatch&lt;/li&gt;&lt;li&gt;You need involvement from all stakeholders to do &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;DDD&lt;/span&gt; to practice the Ubiquitous Language principle.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Concerns (What did I miss)&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Example of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_36"&gt;DDD&lt;/span&gt; applications (or parts of ) to see side-by-side difference. Kurt prepared a lot of example applications to support his viewpoints.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-1396383914108023580?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/1396383914108023580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=1396383914108023580' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1396383914108023580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1396383914108023580'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/visug-devmatch-18102007-datasets-vs-oo.html' title='VISUG-devmatch 18/10/2007 - Datasets vs. OO'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-439443606243257020</id><published>2007-10-17T09:10:00.000+02:00</published><updated>2007-10-18T08:23:10.209+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET design'/><title type='text'>Datasets versus custom objects</title><content type='html'>Here is a list of benefits and concerns for each approach I compiled from various Internet sources and books. If you see other points or disagree with (some) things , don't hestitate to drop a line.&lt;br /&gt;&lt;span style="BACKGROUND-COLOR: #ffff00"&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;Datasets (.NET2.0)&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Disconnnected data-container out-of-the box&lt;/li&gt;&lt;li&gt;Typed datasets enhance ease-of-programming compared to "plain" datasets&lt;/li&gt;&lt;li&gt;Table dataAdpaters automatically generated &lt;/li&gt;&lt;li&gt;Visual designer in VS.NET to create typed datasets manually or via server explorer &lt;/li&gt;&lt;li&gt;Add new data source wizard creates Typed datasets from database schema.&lt;/li&gt;&lt;li&gt;Full two-way data-binding capabilities&lt;/li&gt;&lt;li&gt;Built-in support to receive notifications when something changes inside.&lt;/li&gt;&lt;li&gt;Search/sorting capabilities out-of-the-box (some help of DataView class)&lt;/li&gt;&lt;li&gt;Work together with data adapters to retrieve and persist data.&lt;/li&gt;&lt;li&gt;You can define relationships between tables (referential constraints)&lt;/li&gt;&lt;li&gt;You can define constraint on columns (Uniqueness)&lt;/li&gt;&lt;li&gt;Can hold many kinds of data types (.NET framework)&lt;/li&gt;&lt;li&gt;The DataSet is serializable out-of-the-box (also binary )&lt;/li&gt;&lt;li&gt;Has integrated XML capabilities &lt;/li&gt;&lt;li&gt;Has built-in support for optimistic concurrency&lt;/li&gt;&lt;li&gt;You can add custom logic in typed Dataset partial classes &lt;/li&gt;&lt;li&gt;Using annotations, you can change the names of contained objects to more meaningful names without changing the underlying schema, making code easier for clients to use. &lt;/li&gt;&lt;li&gt;handle NULL values out-of-the box&lt;/li&gt;&lt;li&gt;Lot of third party controls support datasets&lt;/li&gt;&lt;li&gt;Multiple version of a column value can exist and is available out-of-the-box (row state , GetChanges, Merge)&lt;/li&gt;&lt;li&gt;With SQLdataAdapters you can load muliple tables in a dataset at once&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;Concerns&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Everything is represented in .NET Object type. There is a lot of casting/boxing going on&lt;/li&gt;&lt;li&gt;Datasets used in webservices are not ideal from interoperability standpoint&lt;/li&gt;&lt;li&gt;relational API maybe too restrictive (Tables and Relations properties). Need for special methods to represent/manipulate business entities.&lt;/li&gt;&lt;li&gt;DataSet is tied directly to the database model. Abstractions are more diffeiclut . you must adhere to thinking in tables and related concepts.&lt;/li&gt;&lt;li&gt;Inheritance. Your typed dataset must inherit from DataSet, which precludes the use of any other base classes. &lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;Custom Collections&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;provide the means to expose data in easy-to-access APIs without forcing every data model to fit in the relational model. You can still make a one-to-one mapping with the database but you can more easily use OO technisues to model the your problem domain.&lt;/li&gt;&lt;li&gt;Advanced relationships like inheritance are possible.&lt;/li&gt;&lt;li&gt;You can add any behaviour that is needed. Custom entities can contain methods to encapsulate (simple) business rules. Custom entity classes can perform simple validation tests in their property accessors to detect invalid business entity data. &lt;/li&gt;&lt;li&gt;custom class can be marked as serializable &lt;/li&gt;&lt;li&gt;Code can be easier to understand/maintain&lt;/li&gt;&lt;li&gt;LINQ To SQL, Entity Framework are special features in future version of .NET. So MS recognizes benefits of this way of working (or is it under market pressure :)&lt;/li&gt;&lt;li&gt;using custom classes makes for easier unit testing &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;concerns&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Programming effort can be bigger than all-dataset scenario&lt;/li&gt;&lt;li&gt;you must implement a interfaces in order to provide for effective containment and data-binding capabilities&lt;/li&gt;&lt;li&gt;Mapping custom collections and entities to a database can also be a complicated process that can require a significant amount of code (need for code generation/ORM tool)&lt;/li&gt;&lt;li&gt;To support optimistic concurrency time stamp columns must be defined in the database and included as part of the instance data. &lt;/li&gt;&lt;li&gt;Support for multiple versions of data state within an entity must be coded.&lt;/li&gt;&lt;li&gt;No Searching and sorting of data out of the box. You must define your own mechanism to support searching and sorting of entities. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Sources &amp;amp; recommended reading&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;DataSets vs. Collections, Dino Esposito, &lt;a href="http://msdn.microsoft.com/msdnmag/issues/05/08/CuttingEdge/default.aspx"&gt;http://msdn.microsoft.com/msdnmag/issues/05/08/CuttingEdge/default.aspx&lt;/a&gt; &lt;/li&gt;&lt;li&gt;Designing Data Tier Components and Passing Data Through Tiers , MSDN Practices&amp;amp;patterns, &lt;a href="http://msdn2.microsoft.com/en-us/library/ms978496.aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms978496.aspx&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Dataset versus objects, Paul Stovell, &lt;a href="http://www.paulstovell.net/2006/10/18/DataSets+versus+Objects.aspx"&gt;http://www.paulstovell.net/2006/10/18/DataSets+versus+Objects.aspx&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Data Binding with Windows Forms 2.0: Programming Smart Client Data Applications with .NET , Brian Noyes, Microsoft .NET Development Series &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-439443606243257020?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/439443606243257020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=439443606243257020' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/439443606243257020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/439443606243257020'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/datasets-versus-collections.html' title='Datasets versus custom objects'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3846168786247268246</id><published>2007-10-15T09:08:00.000+02:00</published><updated>2007-10-15T09:17:05.930+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SqlServer Integration Services'/><title type='text'>SSIS and RDB</title><content type='html'>Hi,&lt;br /&gt;&lt;br /&gt;Facing some problems with the connectivity towards &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;RDB&lt;/span&gt;, we were looking towards solutions&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Problems&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Schema information did not appear in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;SSIS&lt;/span&gt; wizards/Tools. For example character columns were represented &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;as&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;nvarchar&lt;/span&gt; (0).&lt;/li&gt;&lt;li&gt;Precision with &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;numeric&lt;/span&gt; columns&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;strong&gt;Alternatives&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;After scanning the Internet for solutions, we came up with following alternatives&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Buy a OLE-DB driver for &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;RDB&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;Attunity&lt;/span&gt;)&lt;/li&gt;&lt;li&gt;Emulate &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;RDB&lt;/span&gt; as an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Orcale&lt;/span&gt; Database and use the OLE-Db driver for Oracle&lt;/li&gt;&lt;li&gt;New &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;ODBC&lt;/span&gt; driver for &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;RDB&lt;/span&gt; (3.0) from Oracle.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Fortunately a third option worked for us  (free !) &lt;/p&gt;&lt;p&gt;Check out&lt;br /&gt;&lt;a href="http://www.oracle.com/technology/software/products/rdbodbc/index.html"&gt;http://www.oracle.com/technology/software/products/rdbodbc/index.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Regards,&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Alexander&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3846168786247268246?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3846168786247268246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3846168786247268246' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3846168786247268246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3846168786247268246'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/ssis-and-rdb.html' title='SSIS and RDB'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-1599742464812940368</id><published>2007-10-12T15:47:00.000+02:00</published><updated>2007-10-15T16:41:27.199+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Development Organisation'/><title type='text'>SAI conference : KBC .NET factory</title><content type='html'>&lt;strong&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;KBC&lt;/span&gt; .NET software factory&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Yesterday (11/10/2007) I attended a conference organized by &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;SAI&lt;/span&gt; (www.sai.be) about Agile development and a .NET software factory as used at the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;KBC&lt;/span&gt; group (www.kbc.be) , a banking and &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;insurance&lt;/span&gt; group.&lt;br /&gt;&lt;br /&gt;The &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;presenters&lt;/span&gt; (Peter &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Bauwens&lt;/span&gt;, Jan L&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;aureys&lt;/span&gt;, Kim V&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;erlot&lt;/span&gt;) did a very fine job in &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_8"&gt;explaining&lt;/span&gt; and sharing their experiences with setting up a Software delivery &amp;amp; Maintenance center for .NET application with the KBC .NET software factory .&lt;br /&gt;&lt;br /&gt;I'll try to sum up some point in a benefits &amp;amp; concerns style, meaning the things I '&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;ve&lt;/span&gt; learned and the things I wish I understood better.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Software factories (in the technology sense of the word) alone don't cut it. There is also a process part and an organization(people) part that are equally, if not more , important than the technology at hand.&lt;/li&gt;&lt;li&gt;Pragmatism is key. They were not afraid to mix more "classical" engineering approaches in their agile methodology: The key phrase of Jan was : being agile in an &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_10"&gt;agile&lt;/span&gt; way. for example scrum was expanded with an envisioning and a kind of requirements gathering period. After the scrum sprints, a phase for stabilization and transition was included.&lt;/li&gt;&lt;li&gt;Visual Studio Team foundation was a big enabler in this way of working&lt;/li&gt;&lt;li&gt;Only allow a fixed application architecture with some variability (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;winforms&lt;/span&gt;, Asp.net, batch)&lt;/li&gt;&lt;li&gt;Always question your factory: it is never finished. Incorporate feedback of the developers.&lt;/li&gt;&lt;li&gt;Only work with people who believe in this way of working because not the technology is the biggest hurdle (you have a lot of training possibilities) but the process &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_12"&gt;asks&lt;/span&gt; a particular kind of mentality.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Concerns&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Having authority to impose certain things (process, technology) requires managemente involvement from day one. I wish I knew who I make a business case to invest in a software factory an SDC &amp;amp; Maintenance center&lt;/li&gt;&lt;li&gt;While having a very flat project structure (project administrator, Lead developer, developers) makes communication easy I would say nevertheless I found the "burden" and responsibity they put on the LDEV very big. He combines, in variuos degrees, technology , process and domain knowledge. While writing user stories and talking (and thinking with) the "business" , he also was responsible for keeping the process on track and prefereable also knew the technology. I did not hear anything about system analist or functional analysist or business analist being a part of the team writing the use cases. I wish I knew how I could manage that.&lt;/li&gt;&lt;li&gt;Project assignements go through a process of determing their criticality before being assigned to the development are's withing the KBC group (&lt;strong&gt;Lo&lt;/strong&gt;w level S&lt;strong&gt;LA&lt;/strong&gt; application and &lt;strong&gt;Hi&lt;/strong&gt;gh Level S&lt;strong&gt;LA&lt;/strong&gt; applications). Until now the delivery centers worked on LOLA apps. i wish I knew how I could organise a delivery center for HILA apps with .NET as major technology platform?&lt;/li&gt;&lt;li&gt;The technology pilar changes at a relatively fast pace. When they started in 2005/2006. Some technology from Microsoft wasn't mature enough (Microsoft Software factories) .I wish I knew if it would a safe bet now to go along that path to make our software factory/Delivery center.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Once again, congratualation for the presentors.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Best regards,&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Alexander Nowak&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-1599742464812940368?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/1599742464812940368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=1599742464812940368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1599742464812940368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1599742464812940368'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/sai-conference-kbc-net-factory.html' title='SAI conference : KBC .NET factory'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-1002758452348987014</id><published>2007-10-07T21:56:00.000+02:00</published><updated>2007-10-07T22:24:27.849+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><title type='text'>Unit tests (Part 2)</title><content type='html'>&lt;strong&gt;Working definition&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;Unit testing is a procedure used to validate if “units” of source code are working properly. More technically one should consider that a unit is the smallest testable part of an application. In an Object Oriented program, the smallest unit is a Class or more interesting, its operations.&lt;br /&gt;&lt;br /&gt;Unit testing is done by the developers and not by end-users or separate QA. A unit test is a piece of code that calls the unit under test in particular way in order to find errors during development. Each Unit test verifies if it returns the predicted answer.&lt;br /&gt;&lt;br /&gt;Automation is key in the success of unit testing because it gives the developers a way to create structured unit tests that can be executed easily and repeatable and can be verified through assertions in the test code.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Benefits&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;The goal of unit testing is show that the individual parts of the code are working correctly. In doing unit testing you gain several benefits&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Raise level QA mindset of the developer&lt;/li&gt;&lt;li&gt;Raise confidence in the quality of the code&lt;/li&gt;&lt;li&gt;Tests are run repeatedly&lt;/li&gt;&lt;li&gt;Early warning detection system for programming and/or design errors or flaws&lt;/li&gt;&lt;li&gt;Living documentation on the API of the “units”&lt;/li&gt;&lt;li&gt;Aid for regression testing&lt;/li&gt;&lt;li&gt;Code refactoring is more stimulated&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;When writing unit tests you should think like a tester, not just a developer. The time you take to design your unit tests will help reduce the time spent resolving defects later. Focus on the details of your objects: How is data transferred between them? Who consumes them? How easy can you break the object? What happens if I "do this"?&lt;br /&gt;&lt;br /&gt;When a developer is programming some functionality he usually writes in some way or another some testing code to see whether his implementation does what is supposed to do and if it doesn’t produce errors. The developer then moves on to program the next piece of functionality. Again he assures that run as expected. Maybe the developer moves on other functionalities without coming back to test previous piece of code until release data. With automated unit testing, the developer has a method so the test can be run repeatedly as the code is developed.&lt;br /&gt;&lt;br /&gt;When you have a suite of unit test that effectively test your code, you can be confident that your code will have a low likelihood of errors. The confidence in the quality of the code can be increased.&lt;br /&gt;&lt;br /&gt;The act of writing tests often uncovers design or implementation problems. The unit tests serve as the first users of your system and will frequently identify design issues or functionality that is lacking.&lt;br /&gt;&lt;br /&gt;Once a unit test is written, it serves as a form of documentation for the use of the target system. Other developers can look to unit tests to see example calls into various classes and members.&lt;br /&gt;&lt;br /&gt;Perhaps one of the most important benefits is that a well-written test suite provides the original developer with the freedom to pass the system off to other developers for maintenance and further enhancement. Should those developers introduce a bug in the original functionality, there is a strong likelihood that those unit tests will detect that failure and help diagnose the issue. Meanwhile, the original developer can focus on current tasks.&lt;br /&gt;&lt;br /&gt;It takes the typical developer time and practice to become comfortable with unit testing. Once a developer has been saved enough time by unit tests, he or she will latch on to them as an indispensable part of the development process.&lt;br /&gt;&lt;br /&gt;Unit testing does require more explicit coding, but this cost will be recovered, and typically exceeded, when you spend much less time debugging your application. In addition, some of this cost is typically already hidden in the form of test console- or Windows-based applications. Unlike these informal testing applications, which are frequently discarded after initial verification, unit tests become a permanent part of the project, run each time a change is made to help ensure that the system still functions as expected. Tests are stored in source control very near to the code they verify and are maintained along with the code under test, making it easier to keep them synchronized.&lt;br /&gt;&lt;br /&gt;Unit tests are an essential element of regression testing. Regression testing involves retesting a piece of software after new features have been added to make sure that new bugs are not introduced. Regression testing also provides an essential quality check when you introduce bug fixes in your product.&lt;br /&gt;&lt;br /&gt;It is difficult to overstate the importance of comprehensive unit test suites. They enable a developer to hand off a system to other developers with confidence that any changes they make should not introduce undetected side effects. However, because unit testing only provides one view of a system's behavior, no amount of unit testing should ever replace integration, acceptance, and load testing.&lt;br /&gt;&lt;br /&gt;In the same line but when refactoring code (changing code without changing the intend) to improve design in terms of maintainability, performance, etc. are more stimulated if you have a battery of unit tests. You’re more confident when you refactor some code. You can easily check if the code change is done correctly.&lt;br /&gt;&lt;br /&gt;Automated unit testing should help reduce the amount of time you spend in the debugger. However, if testing results and code coverage do not help in providing the reason why your test is failing, don't be afraid to debug your unit tests. In Visual Studio 2005 Team System, developers can debug their unit testing assemblies using the Debug Selected tests option in Test Manager. You can also debug Nunit test.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Concerns &lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Unit testing will not catch every error in the program. By definition, it only tests the functionality of the units themselves. Therefore, it will not catch integration errors (except when you consider a component or subsystem as a unit) , performance problems or any other system-wide issues. In addition, it may not be easy to anticipate all special cases of input the program unit under study may receive in reality. Unit testing is only effective if it is used in conjunction with other software testing activities.&lt;br /&gt;&lt;br /&gt;It is unrealistic to test all possible input combinations for any non-trivial piece of software. Like all forms of software testing, unit tests can only show the presence of errors; it cannot show the absence of errors. Writing unit tests for every single class to test every aspect of every function is a tall order. Even with a large number of unit tests, is complete testing possible (or desirable)?&lt;br /&gt;&lt;br /&gt;What if there are bugs in the unit tests? Where there is code, there will be bugs. You’ll be getting false positives.&lt;br /&gt;&lt;br /&gt;Not all code can be unit tested (at least not easily). It could, of course, be argued that in this case, the code should be simplified until it can be unit tested.&lt;br /&gt;Passing a Unit test only means that no the test it self did not catch any problem. All the assertions were correct. This doesn’t mean that there are no bugs. The success depends on the quality of the unit test as well.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Automation&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Unit testing in spirit has existed since the beginning of programming. Every environment, development shop or even programmer had/has its way of conducting these kinds of tests. For example creating a form with 20 –odd buttons calling various part of your code base.&lt;br /&gt;This “Form with buttons where each button performs a functionality of the code to be tested” –approach work s but you need a manual operation for each single test: clicking the button. The main problem is that you need to have the discipline to click on very button after very change. Secondly, it is very easy to drag a button on a form and hook and eventhandler leaving the name of the button to its default. If you revisit the form a after some time, chances are you don’t remember to meaning behind the button. It will be even more difficult for someone else interpreting the test behind all the buttons. Thirdly, knowing if the test succeeded or not , you had to make assertions in your code , or make the assertion visually but also you needed a way to give feedback to the developer ( eg infamous msgbox).&lt;br /&gt;&lt;br /&gt;Third-party vendors of course offer solutions to the testing problems but they are usually very expensive and introduce their own, proprietary scripting language to conducts test.&lt;br /&gt;&lt;br /&gt;The xUnit framework was introduced as a core concept of eXtreme Programming in 1998. It introduced an efficient mechanism to help developers add structured, efficient, automated unit testing into their normal development activities. This Toolkit lets you develop tests using the same language and IDE that they are using to develop the application. The xUnit framework defines concept of "test runner" as the application responsible for (a) executing unit tests, and (b) reporting on the test results. Automated unit tests are based on "assertions," which can be defined as "the truth, or what you believe to be the truth." From a logic standpoint, consider this statement, "when I do {x}, I expect {y} as a result."&lt;br /&gt;&lt;br /&gt;The atomic parts of a unit test fixture are the test methods that make assertions about the behavior of some (or all) public members of the unit you're testing. A test suite is a library assembly that contains one or more such test fixtures, along with optional setup and teardown methods. You normally run this assembly from a GUI app, but these unit tests can run also from a command-line and be activated from other applications (build process).&lt;br /&gt;&lt;br /&gt;With the help of this testing automation framework your unit tests are&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Test can be written in same language as the tested unit&lt;/li&gt;&lt;li&gt;Structured. &lt;/li&gt;&lt;li&gt;Self-documenting. &lt;/li&gt;&lt;li&gt;Automatic and repeatable. &lt;/li&gt;&lt;li&gt;Designed to test positive and negative actions.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Open questions&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Testing should become an integral part of the programming effort , not some things that comes afterwards. But how can you educate your team? How can you convince management&lt;/li&gt;&lt;li&gt;How to ensure that having a lot of unit tests does in fact make tracking bugs easier?&lt;/li&gt;&lt;li&gt;How to make sure your tests are easy to maintain?&lt;/li&gt;&lt;li&gt;How to write readable unit tests&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;References and recommend reading&lt;br /&gt;&lt;/strong&gt;&lt;p&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Write Maintainable Unit Tests That Will Save You Time And Tears, Roy Osherove &lt;a href="http://msdn.microsoft.com/msdnmag/issues/06/01/UnitTesting/"&gt;http://msdn.microsoft.com/msdnmag/issues/06/01/UnitTesting/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Qualities of a Good Unit Test &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/07/20/129552.aspx"&gt;http://codebetter.com/blogs/jeremy.miller/archive/2005/07/20/129552.aspx&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Coder to Developer: Tools and Strategies for Delivering Your Software , Mike Gunderloy , ISBN:078214327X&lt;/li&gt;&lt;li&gt;Pro Visual Studio 2005 Team System ,Jeff Levinson and David Nelson , ISBN:1590594606&lt;/li&gt;&lt;li&gt;.NET 2.0 for Delphi Programmers ,Jon Shemitz , ISBN:1590593863&lt;/li&gt;&lt;li&gt;Extreme Programming Refactored: The Case Against XP Matt Stephens and Doug Rosenberg ISBN:1590590961&lt;/li&gt;&lt;li&gt;Professional Visual Studio 2005 Team System ,Jean-Luc David et al. ISBN:0764584367&lt;/li&gt;&lt;li&gt;Code Complete: A Practical Handbook of Software Construction ,Steve McConnell , ISBN:1556154844&lt;/li&gt;&lt;li&gt;Test-Driven Development in Microsoft .NET, James W. Newkirk and Alexei A. Vorontsov ,ISBN:0735619484&lt;/li&gt;&lt;li&gt;Pragmatic Unit Testing in C# with NUnit: The Pragmatic Starter Kit, Volume II (Volume Set) , Andy Hunt and Dave Thomas ,ISBN:0974514020&lt;/li&gt;&lt;li&gt;Why Agile Software Development Techniques Work: Improved Feedback: &lt;a href="http://www.ambysoft.com/essays/whyAgileWorksFeedback.html"&gt;http://www.ambysoft.com/essays/whyAgileWorksFeedback.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Unit_testing"&gt;http://en.wikipedia.org/wiki/Unit_testing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;The Humble Dialog Box (http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf )&lt;/li&gt;&lt;li&gt;NUnit (http://www.nunit.org/ )&lt;/li&gt;&lt;li&gt;&lt;a href="http://martinfowler.com/eaaDev/uiArchs.html"&gt;http://martinfowler.com/eaaDev/uiArchs.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-1002758452348987014?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/1002758452348987014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=1002758452348987014' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1002758452348987014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/1002758452348987014'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/unit-tests-part-2.html' title='Unit tests (Part 2)'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-3251618058627048675</id><published>2007-10-05T12:56:00.000+02:00</published><updated>2007-10-23T10:51:41.601+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><title type='text'>Testing types classification</title><content type='html'>&lt;div&gt;There are different types of test you can conduct. These test types have different objectives and characteristics. There are several classification criteria to organize these types of test.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Who uses the information of the test results? (development team, end-user, operations , Audit firms, etc)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Phase in development cycles (Requirements gathering, Analysis, Design , Construction , etc)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Phase in life cycle of a application (New versus maintenance)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Who establishes and/or executes the test? (Development team, Test organization, end-user)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Dynamic tests versus static tests&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Functional test versus non-functional test (performance, load, security ,etc)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Sometimes the classification name for type means one thing for one person and another for person. I tried to compile a list of test types from several Internet resources and books. I don't give any formal definition but try to specify the test type through its characteristics.&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Objective&lt;/li&gt;&lt;br /&gt;&lt;li&gt;How are the tests executed?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Who executes the tests?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Who is the main interesseted party in the test-results?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Where are the tests executed?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;When are the tests executed?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;img id="BLOGGER_PHOTO_ID_5124450592356233314" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/Rx20qcpu8GI/AAAAAAAAAF8/2F1t_-a03QU/s400/TestingTypes.JPG" border="0" /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Static testing&lt;br /&gt;&lt;/p&gt;&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;To find errors before they become bugs early in the software development cycle.&lt;/li&gt;&lt;li&gt;Code is not being executed.&lt;/li&gt;&lt;li&gt;Usually take the form of code reviews (self-review, peer–review, walk-troughs, inspections, audits) BUT can also be conducted on level of requirements, analysis and design.&lt;/li&gt;&lt;li&gt;Usage of check-list for verification.&lt;/li&gt;&lt;li&gt;Code analysis preferably executed through tools.&lt;/li&gt;&lt;li&gt;Executor : Individual developer , Development team, Business analyst / Customer in case of requirements testing ,Business analyst in case of analysis reviews, Architect/Senior designer in case of design review&lt;/li&gt;&lt;li&gt;Primary beneficiary is the project team self&lt;/li&gt;&lt;li&gt;Can be executed on the private development environment&lt;/li&gt;&lt;li&gt;Can be executed in separate environment ( test environment , build environment in Continuous Integration scenario)&lt;/li&gt;&lt;li&gt;Code review usually in construction phase; Audits tend to be later in the cycle.&lt;/li&gt;&lt;li&gt;Reviews on requirements, analysis and design are executed early in the project&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Unit testing&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A.k.a. Program testing , Developer testing&lt;/li&gt;&lt;li&gt;The main objective is to eliminate coding errors&lt;/li&gt;&lt;li&gt;Testing the smallest unit in programming environment (class , function , module)&lt;/li&gt;&lt;li&gt;Typically the work of one programmer&lt;/li&gt;&lt;li&gt;In OO environment usage of Mock Libraries/Stubs to isoloated units&lt;/li&gt;&lt;li&gt;Executed by the developer&lt;/li&gt;&lt;li&gt;Feedback immediately used by the developer. &lt;/li&gt;&lt;li&gt;Test results are not necessarly logged somewhere.&lt;/li&gt;&lt;li&gt;Executed on the private development environment. So Tested in isolation of others developers.&lt;/li&gt;&lt;li&gt;But can be executed in separate environment ( build environment in Continuous Integration scenario)&lt;/li&gt;&lt;li&gt;Executed during construction phase&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Unit Integration testing&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A.k.a. Component testing, Module testing&lt;/li&gt;&lt;li&gt;To check if units can work together&lt;/li&gt;&lt;li&gt;It is possible for units to function perfectly in isolation but to fail when integrated&lt;/li&gt;&lt;li&gt;Typically the work of one programmer &lt;/li&gt;&lt;li&gt;Executed by the Developer&lt;/li&gt;&lt;li&gt;Test results immediatly used by Developer&lt;/li&gt;&lt;li&gt;Test results are not necessarly logged somewhere.&lt;/li&gt;&lt;li&gt;Executed on the private development environment. So Tested in isolation of others developers.&lt;/li&gt;&lt;li&gt;Can be executed in separate environment ( build environment in Continuous Integration scenario)&lt;/li&gt;&lt;li&gt;Exectued during construction phase&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;System testing&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Compares the system or program to the original objectives&lt;/li&gt;&lt;li&gt;Verification with a written set of measurable objectives&lt;/li&gt;&lt;li&gt;Focuses on defects that arise at this highest level of integration.&lt;/li&gt;&lt;li&gt;The execution of the software in its final configuration, including integration with other software and hardware systems&lt;/li&gt;&lt;li&gt;Includes many types of testing: usually strong distinction between functional and non-functional requirements like usability, security, localization, availability, capacity, performance, backup and recovery, portability&lt;/li&gt;&lt;li&gt;Who's testing depends on sub type but usually a separate tester role within the project team&lt;/li&gt;&lt;li&gt;Test results are used by the Project team or Operations (performance , volume , -&gt; capacity)&lt;/li&gt;&lt;li&gt;Executed on the separate test environment&lt;/li&gt;&lt;li&gt;Generally &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;executed&lt;/span&gt; towards the end of construction when main functionality is working.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Functional testing&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Finding discrepancies between the program and its external specification&lt;/li&gt;&lt;li&gt;Test result used &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;primarily&lt;/span&gt; by the project team&lt;/li&gt;&lt;li&gt;focuses on validating the features of an entire function (use case)&lt;/li&gt;&lt;li&gt;Main question: Is it performing as our customers would expect?&lt;/li&gt;&lt;li&gt;White box approach&lt;/li&gt;&lt;li&gt;Single-user test. It &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;does no&lt;/span&gt;t attempt to emulate simultaneous users&lt;/li&gt;&lt;li&gt;Look at the software through the eyes of targeted end-user.&lt;/li&gt;&lt;li&gt;Preferable separate tester (non-biased)&lt;/li&gt;&lt;li&gt;Separate test environment&lt;/li&gt;&lt;li&gt;Generally more towards the end of construction&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Beta testing&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Check how the software affects the business when a real customers use the software &lt;/li&gt;&lt;li&gt;"Test results" used by customer and project team&lt;/li&gt;&lt;li&gt;Usually not a completely finished product&lt;/li&gt;&lt;li&gt;Sometimes used in parallel with previous application on the end-user environment.&lt;/li&gt;&lt;li&gt;Is usually not structured testing. No real test cases established. Application is used in everyday scenarios. Although some end-users use implicit error guessing techniques to discover defects.&lt;/li&gt;&lt;li&gt;Executed by selected end-users&lt;/li&gt;&lt;li&gt;In separate test environment or real &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;production&lt;/span&gt; environment&lt;/li&gt;&lt;li&gt;It can be conducted after some construction (iterations) but normally before formal acceptance tests.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Acceptance Testing&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Executed by the Customer or some appointed by the customer (Not the delivering party)&lt;/li&gt;&lt;li&gt;Determine if software meets customer requirements and to whether the user accepts (read pays) for the application.&lt;/li&gt;&lt;li&gt;Who defines the depth of the acceptance testing? &lt;/li&gt;&lt;li&gt;Who creates the test cases?&lt;/li&gt;&lt;li&gt;Who actually executes the tests? &lt;/li&gt;&lt;li&gt;What are the pass/fail criteria for the acceptance test? &lt;/li&gt;&lt;li&gt;When and how is payment arranged?&lt;/li&gt;&lt;li&gt;Test results &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;primarily&lt;/span&gt; used by customer but are handed over to project team . Could be that application is accepted under some conditions . A.k. known bugs.&lt;/li&gt;&lt;li&gt;Separate test environment or Production environment&lt;/li&gt;&lt;li&gt;Executed after complete testing by delivering party&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Performance testing&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Searches for bottlenecks that limit the software’s response time and throughput&lt;/li&gt;&lt;li&gt;Results &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_5"&gt;primarily&lt;/span&gt; used by development team and Operations&lt;/li&gt;&lt;li&gt;To identify the degradation in software that is caused by functional bottlenecks and to measure the speed at which the software can execute&lt;/li&gt;&lt;li&gt;Kind of system test&lt;/li&gt;&lt;li&gt;Mimic real processing patterns , mimic production-like situations&lt;/li&gt;&lt;li&gt;To identify performance strengths and weaknesses by gathering precise measurements&lt;/li&gt;&lt;li&gt;Don’t intentionally look for functional defects&lt;/li&gt;&lt;li&gt;Executed by separate test role&lt;/li&gt;&lt;li&gt;Executed on the separate test environment&lt;/li&gt;&lt;li&gt;Generally toward the end of construction unless performance-critical components are identified beforehand (calculations, external connectivity through WAN/Internet, etc)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Usability testing&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Check if human Interface complies with the standards at hand and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;UI&lt;/span&gt; is easy to work with&lt;/li&gt;&lt;li&gt;Kind of system test&lt;/li&gt;&lt;li&gt;Test results serve the development team and end user&lt;/li&gt;&lt;li&gt;Components generally checked include screen layout, screen colours, output formats, input fields, program flow, spellings, Ergonomics , Navigation , and so on&lt;/li&gt;&lt;li&gt;Preferable separate tester (non-biased) conducts these test (speciality)&lt;/li&gt;&lt;li&gt;Executed on the separate test environment&lt;/li&gt;&lt;li&gt;Generally toward the end of construction&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;System Integration testing&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;To check if several sub-system can work together as specified&lt;/li&gt;&lt;li&gt;Kind of system test&lt;/li&gt;&lt;li&gt;Development team&lt;/li&gt;&lt;li&gt;Larger-scale integration than unit integration&lt;/li&gt;&lt;li&gt;Generally combines the work of several programmers.&lt;/li&gt;&lt;li&gt;Separate test role with the project team (delivering party)&lt;/li&gt;&lt;li&gt;Test result used by project team&lt;/li&gt;&lt;li&gt;Executed on the separate test environment&lt;/li&gt;&lt;li&gt;During construction when workable sub-systems are ready to be tested (i.e. basic &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_7"&gt;functionality&lt;/span&gt; works in happy path)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Security testing&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Tries to compromise the security mechanisms of an application or system.&lt;/li&gt;&lt;li&gt;Kind of system test&lt;/li&gt;&lt;li&gt;Need for separate test environment to mimic production environment&lt;/li&gt;&lt;li&gt;Separate test role&lt;/li&gt;&lt;li&gt;Executed at end of construction unless is &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_8"&gt;primordial&lt;/span&gt; in the application&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Volume testing&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Other terms or specialisations Scalability testing, Load testing, Capacity testing&lt;/li&gt;&lt;li&gt;To determine whether the application can handle the volume of data specified in its objectives (current + future). So what happens to the system when a certain volume is processed over a longer period of time (resource leaks, etc)&lt;/li&gt;&lt;li&gt;Test results important for project team and Operations&lt;/li&gt;&lt;li&gt;Volume testing is not the same as stress testing (tries to break the application)&lt;/li&gt;&lt;li&gt;Separate test role&lt;/li&gt;&lt;li&gt;Executed on the separate test environment&lt;/li&gt;&lt;li&gt;Generally towards end of construction unless load/scalability is a critical &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_9"&gt;success&lt;/span&gt; factor&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Stress testing&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;To find the limits of the software regarding peak data volumes or maximum number of concurrent users&lt;/li&gt;&lt;li&gt;&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_10"&gt;Interested&lt;/span&gt; parties are : Project team and Operations&lt;/li&gt;&lt;li&gt;Create chaos is the key premises.&lt;/li&gt;&lt;li&gt;Go beyond potential processing patterns&lt;/li&gt;&lt;li&gt;Try to demonstrate that an application does not meet certain criteria such as response time and throughput rates, under certain workloads or configurations &lt;/li&gt;&lt;li&gt;Kind of system test&lt;/li&gt;&lt;li&gt;Don’t look for functional defects (intentionally)&lt;/li&gt;&lt;li&gt;Need for separate test environment to mimic production environment&lt;/li&gt;&lt;li&gt;Special test software used to simulate load /concurrent users&lt;/li&gt;&lt;li&gt;Separate test role&lt;/li&gt;&lt;li&gt;End of construction&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Availability testing&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;To assure that our application can continue functioning when certain type of faults occur.&lt;/li&gt;&lt;li&gt;Test in function of fail-over technology.&lt;/li&gt;&lt;li&gt;Don’t look for functional defects (intentionally)&lt;/li&gt;&lt;li&gt;Need for separate test environment to mimic production environment&lt;/li&gt;&lt;li&gt;Special test software used to simulate certain fault(network outage, etc)&lt;/li&gt;&lt;li&gt;Separate test role&lt;/li&gt;&lt;li&gt;End of construction &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Deployment testing&lt;br /&gt;&lt;/p&gt;&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A.k.a Installation testing&lt;/li&gt;&lt;li&gt;To verify installation procedures&lt;/li&gt;&lt;li&gt;Important for Release manager and Operations (&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_11"&gt;start up&lt;/span&gt;/ business continuity)&lt;/li&gt;&lt;li&gt;checking automated installation programs&lt;/li&gt;&lt;li&gt;Configuration meta data&lt;/li&gt;&lt;li&gt;Installation manual review&lt;/li&gt;&lt;li&gt;Conducted by separate test role&lt;/li&gt;&lt;li&gt;Separate environment by default (clean machine principle)&lt;/li&gt;&lt;li&gt;Construction during stage promotion for example&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Regression testing&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;To avoid that software goes into regression in light of changes or bug fixes&lt;/li&gt;&lt;li&gt;Regression bugs occur whenever software functionality that previously worked as desired stops working or no longer works in the same way that was previously planned. Typically regression bugs occur as an unintended consequence of program changes&lt;/li&gt;&lt;li&gt;To make sure a fix/change correctly resolves the original problem reported by the customer. &lt;/li&gt;&lt;li&gt;To ensure that the fix/change &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;does no&lt;/span&gt;t break something else.&lt;/li&gt;&lt;li&gt;On different levels Unit, integration , system, functional&lt;/li&gt;&lt;li&gt;Executor depends on level of test&lt;/li&gt;&lt;li&gt;Primary &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_13"&gt;interested&lt;/span&gt; party depends on level of test&lt;/li&gt;&lt;li&gt;&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_14"&gt;Executed&lt;/span&gt; during Construction or Maintenance&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Several Other Specialised tests&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Testing for operational monitoring: Do faults we simulated find their way in the monitoring environment of our application?&lt;/li&gt;&lt;li&gt;Testing for portability: Does our product work on the targeted Operation Systems?&lt;/li&gt;&lt;li&gt;Testing for interoperability;For example does our software work with different targeted database systems?&lt;/li&gt;&lt;li&gt;Testing the localized versions.&lt;/li&gt;&lt;li&gt;Testing for recoverability after certain system failures.&lt;/li&gt;&lt;li&gt;etc.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-3251618058627048675?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/3251618058627048675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=3251618058627048675' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3251618058627048675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/3251618058627048675'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/testing-types-classification.html' title='Testing types classification'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_GROsRPS-U-k/Rx20qcpu8GI/AAAAAAAAAF8/2F1t_-a03QU/s72-c/TestingTypes.JPG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-6581209380845185431</id><published>2007-10-04T09:13:00.000+02:00</published><updated>2007-12-14T16:12:41.946+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><title type='text'>Test Specification techniques</title><content type='html'>&lt;strong&gt;Context &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I assembled some information about techniques you can use to specify the test cases to see whether the code contains errors while assuring that the test cases covered all the code and possible conditions.&lt;br /&gt;&lt;br /&gt;Generally the techniques are divided in two groups ; Black-box and white-box testing techniques where black-box techniques treat the unit only from an API standpoint and the white-box techniques require full understanding of the code.&lt;br /&gt;&lt;br /&gt;It is important to note that some formal techniques can take a lot of effort to so I suggest a more pragmatic approach based on a combination of techniques.&lt;br /&gt;&lt;br /&gt;There are different kinds of testing but for the discussion of this text we will use the following taxonomy.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Unit testing is a process of testing the individual subprograms (classes), subroutines or procedures (methods) in a program. Most of the times these “units” are tightly coupled with other modules. Sometimes the latter are stubbed out to assure that we only test the unit under test and not the secondary units. Unit integration testing concerns the inter-operation between the different units a developer has made.&lt;/li&gt;&lt;li&gt;Component testing or subsystem testing  (unit integration) verifies a particular portion of the application, for example the data access layer code. This for example requires the integration of a database server.&lt;/li&gt;&lt;li&gt;System test is a higher level test that verifies non-functional characteristics at the entry point of a system. For example performance, stress, volume, etc.&lt;/li&gt;&lt;li&gt;Functional tests test the system much like a client would use the application. Things like the order of input , user error messages , etc&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some of the techniques discussed are more fit for a particular type of testing than others . I will concentrate on the techniques you could use in developer testing (unit and unit integration testing).&lt;/p&gt;&lt;strong&gt;Test psychology&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is testing something we do to show that a piece program is working as expected or that it contains no errors or to find (all) errors? Or everything mentioned?&lt;br /&gt;&lt;br /&gt;This might seem like subtle differences in semantics to some readers but it is actually quite strong because it gives you a different starting point while specifying test cases. Testing should have something destructive in nature. You’re going to write test cases to break the code; At least that should be your mindset while testing.&lt;br /&gt;&lt;br /&gt;Testing has the purpose of increasing the reliability of your code. So actually when a test case finds an error , the test case should be mentally regarded as a success because it found an error and we can fix it before it was put through acceptance testing or worse, in production. Of course the meaning of success is double-faced because once we fix the code and execute the test case again we should not find the error anymore. The test-case passed successfully, meaning this time processing the correct result.&lt;br /&gt;So saying that my piece of code is working as expected so not the ideal mindset because you can more easily write test case that will demonstrate that. That being said these “positive attitude“ test cased should nevertheless be included into your collection test cases to assure you code coverage objective.&lt;br /&gt;&lt;br /&gt;Proving that your program contains no errors is very difficult to state because the psychological burden to achieve this is too big for a programmer. It is better to uncover as much as errors as possible. By increasing the test case you have, you’re more likely to find more errors. The more errors you find, an of course fix, the more confident you will be of your code. This will reduce the stress you’re feeling.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Typical Software defects and their causes&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;This is a huge area but ranging from wrong error messages to unable to free unused memory or missing database fields because of incomplete specifications. I will narrow the list to some typical coding errors and their sources.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Error against numeric boundaries&lt;/li&gt;&lt;li&gt;Wrong number of loops&lt;/li&gt;&lt;li&gt;Wrong values for constants&lt;/li&gt;&lt;li&gt;Wrong operation order&lt;/li&gt;&lt;li&gt;Overflows&lt;/li&gt;&lt;li&gt;Incorrect operator used in comparison &lt;/li&gt;&lt;li&gt;precision loss due to rounding or truncation&lt;/li&gt;&lt;li&gt;Unhandled case in logic&lt;/li&gt;&lt;li&gt;Failure to initialize a loop control variable&lt;/li&gt;&lt;li&gt;Failure to (re)initialize&lt;/li&gt;&lt;li&gt;Assuming one event always finishes before another&lt;/li&gt;&lt;li&gt;Required resource not available&lt;/li&gt;&lt;li&gt;Doesn't free unused memory&lt;/li&gt;&lt;li&gt;Device unavailable&lt;/li&gt;&lt;li&gt;Unexpected end of file&lt;/li&gt;&lt;li&gt;Wrong data types used&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;p&gt;&lt;a name="_Toc173810640"&gt;&lt;strong&gt;Test strategies&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;So how should we go about finding all errors in a program? We could try it by using every possible input condition as a test case. This would lead quickly to huge amounts of test cases with usually negligible added value. So what is out test-case design strategy?&lt;/p&gt;&lt;p&gt;One important testing strategy is black-box testing. Your goal is to be completely unconcerned about the internal behaviour and structure of the program. Instead, concentrate on finding circumstances in which the program does not behave according to its specifications. In this approach, test cases are derived solely from the specifications (i.e., without taking advantage of knowledge of the internal structure of the program). &lt;/p&gt;&lt;p&gt;Another testing strategy, white-box testing, forces you to examine the internal structure of the program. This strategy derives test data from an examination of the program’s logic.&lt;br /&gt;In finding test cases, the following paragraphs sum up several techniques you can use to find appropriate test cases. It is not a “cook-book –like” description. It merely tries to serve as a reminders when you faced with coming up with test cases. &lt;/p&gt;&lt;p&gt;It neither a mutually exclusive set of techniques. As a matter a fact, the recommended procedure for example unit testing is to develop test cases using the black-box methods and then develop supplementary test cases as necessary with white-box methods.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Sources for test case specification&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p align="left"&gt;&lt;img id="BLOGGER_PHOTO_ID_5117384215808110610" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/RwSZ1Mpu8BI/AAAAAAAAAFU/592e_UeN3Vc/s400/testcasesources.JPG" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Depending on the type test some sources are more appropriate than others .&lt;/p&gt;&lt;br /&gt;&lt;strong&gt;Equivalence classes&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Exhaustive-input test of a program is impossible. Hence, in testing a program, you are limited to trying a small subset of all possible inputs. Of course, then, you want to select the right subset, the subset with the highest probability of finding the most errors. Instead of randomly selecting a subset, you can structure your effort with technique called equivalence partioning.The equivalence classes are identified by taking each input condition (a sentence or phrase in the specification, or a parameter of a method) and partitioning it into two or more groups. An equivalence class consists of a set of data that is treated the same by the module or that should produce the same result. Two types of equivalence classes can be identified: valid equivalence classes represent valid inputs to the program, and invalid equivalence classes represent all other possible states of the condition (i.e., erroneous input values).These equivalence classes will form the basis for your test cases and test case data&lt;br /&gt;&lt;br /&gt;Here are some examples&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5117395361248243794" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/RwSj98pu8FI/AAAAAAAAAF0/fsWgu5798eE/s400/equivalence.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Boundary value analysis&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Boundary conditions are those situations directly on, above, and beneath the edges of input equivalence classes and output equivalence classes. Boundary value testing focuses on the boundaries simply because that is where so many defects hide. For example using &gt; (greater than) in a condition instead of &gt;= (greater than or equal as). "Below" and "above" are relative terms and depend on the data value's units. So rather than selecting any element in an equivalence class as being representative, boundary-value analysis requires that one or more elements be selected such that each edge of the equivalence class is the subject of a test.Another attention point is that rather than just focusing attention on the input conditions (input space), test cases are also derived by considering the result space (output equivalence classes). For example for determining the percentage of discount for a particular order, you could try to come up with a test case that would possible generate a discount more than the foreseen maximum discount. These boundary values will be the test case data values.&lt;br /&gt;&lt;br /&gt;Here are some examples.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5117394570974261314" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_GROsRPS-U-k/RwSjP8pu8EI/AAAAAAAAAFs/b-MXb5n7GmA/s400/boundaries.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Decision table testing&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In equivalence Class and Boundary Value testing we considered the testing of individual variables that took on values within specified ranges. Sometimes value of one variable constrains the acceptable values of another. In this case, certain defects cannot be discovered by testing them individually.This technique explores the combinations of input circumstances to come up with test cases.The testing of input combinations is not a simple task because the number of combinations can grow quicklyIf you have no systematic way of selecting a subset of a combination of input conditions, you’ll probably select an arbitrary subset of conditions, which could lead to an ineffective test.Decision tables represent actions that have to be taken based on a set of conditions. These are actually the rules. Each rule defines a unique combination of conditions that result in the execution ("firing") of the actions associated with that rule (If this and that is true than do this). If the system under test has complex business rules, presenting the system behaviour represented in this complete and compact form enables you to create test cases directly from the decision table.Create at least one test case for each rule. If the rule's conditions are binary, a single test for each combination is probably sufficient. On the other hand, if a condition is a range of values, consider testing at both the low and high end of the range. In this way we merge the ideas of Boundary Value testing with Decision Table testing.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Consider following psuedo-code &lt;/p&gt;&lt;img id="BLOGGER_PHOTO_ID_5117390778518138914" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_GROsRPS-U-k/RwSfzMpu8CI/AAAAAAAAAFc/fSanNrPrl1Y/s400/pseudocode.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5117391663281401906" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_GROsRPS-U-k/RwSgmspu8DI/AAAAAAAAAFk/iYCIKgn6Y_g/s400/decisiontable.JPG" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This exercise shows us that we need at least 18 different test case data sets to test all the logic.&lt;br /&gt;You can merge this with explicit boundary checks.&lt;br /&gt;Qty = 0, Qty = 9, qty= 10, qty = 11, qty = 14, qty = 15, qty = 16&lt;br /&gt;Km = 0, km =49, km= 50, km = 51, km =99, km = 100, km=101&lt;br /&gt;Of course combinations between them are also possible. You could even try a test with negative quantity to see if the code can handle that situation. &lt;/p&gt;&lt;p&gt;This all depends if you can look into the code to see how the decision tree is actually implemented. Some situations will result in the same outcome. You could decide to collapse the table. But be careful with collapsed tables. While this is an excellent idea to make the table more comprehensible it is dangerous from a testing standpoint. It is always possible that the table was collapsed incorrectly or the code was written improperly. Try to use, if possible, the un-collapsed table as the basis for your test case design.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Control flow testing&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Modules of code are converted to graphs, the paths through the graphs are analyzed, and test cases are created from that analysis. This techniques requires are lot of preparation. Maybe usefull for safety -critical applications.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Depth of test specification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Some factors that come into play of determining the appropriate amount of testing effort (test case, time, depth , etc)&lt;br /&gt;Cost of failure&lt;br /&gt;Testability of the design&lt;br /&gt;Life cycle of the application ; new or maintenance&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Programming language&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Sometimes the data types available in your programming language can help you reduce the number of test cases. Suppose you have a method in VB.NET that accepts an integer value that, according to the specs, must between 0 and 100. In case of the boundary values we can actually help reduce the number of test case because in VB.NET we have the possibility to use an unsigned integer data type (UInteger). It simply can not hold negative numbers so consequently we don’t have to specify a test that gives a negative number to the method.Enumerations can also help.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Design-by contract&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;In the design-by-contract approach, modules (called "methods" in the object-oriented paradigm, but "module" is a more generic term) are defined in terms of pre-conditions and post-conditions. Post-conditions define what a module promises to do (compute a value, open a file, print a report, update a database record, change the state of the system, etc.). Pre-conditions define what that module requires so that it can meet its post-conditions.More the code must use a mechanism to assert that these pre – and post conditions are met. Usually these assertions are placed inside the method. In this case the module is designed to accept any input. If the normal preconditions are met, the module will achieve its normal post conditions. If the normal pre-conditions are not met, the module will notify the caller by returning an error code or throwing an exception (depending on the programming language used). This notification is actually another one of the module's post conditions.Based on this approach we could define defensive testing: an approach that tests under both normal and abnormal pre-conditions. On the other hand if we trust the assertion mechanism we could go about and create test cases only for the situations in which the pre-conditions are met.&lt;br /&gt;There are programming environments where the specification of pre-and post conditions are integrated directly in the language or language execution environment.&lt;br /&gt;Should we create test cases for invalid input?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Difficult test conditions&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Often modules have code that is executed only in exceptional circumstances—low memory, full disk, unreadable files, lost connections, Database locking, high network load etc. You may find it difficult or even impossible to simulate these circumstances and thus code that deals with these problems will remain untested. Still you would like to know how your code and more over your error handling code reacts on these situations.It is recommend to write that test case down and make the remark that the situation has not been tested.There are tools on the market that can help you simulate some of these conditions and check how your program reacts. For example DevPartner Fault Simulator 2.0. For example using DevPartner Fault Simulator you could observe how the application would handle the failures generated by a simulated network failure instead of you physically disconnecting a cable from the network,&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Code coverage analysis&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;While the previous sections described techniques to specify test cases before or during programming, a code coverage analysis tool investigates your code during the execution of the current set of test cases (assuming you did some upfront test case design) if all code regions have been covered by the sets of test. It can point you the certain code path that haven’t been covered by the current set of test cases. It gives you the opportunity to specify new test case that will execute that part of your code. It can help you to eliminate gaps in your test suite.It is important to note that 100% code coverage does not equal to the fact that all errors are removed from your piece of code. It merely states that all code paths have been gone trough with your current test case suite. You still can miss out on errors simply because you’ve used a wrong comparisons operator ( &gt; instead of &gt;=) . So the previous techniques are still valuable. Code coverage gives you additional information that you can use. It just one of the methods to maximize the ability to find the errors in your code.Microsoft research is currently working on a tool that augments code coverage analysis with the creation of missing test case. Pex performs a systematic program analysis. It records detailed execution traces of existing test cases. Pex learns the program behaviour from the execution traces, and a constraint solver produces new test cases with different behaviour. The result is a test suite with maximal code coverage&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Concluding remarks&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Writing effective test cases is hard work and not always that easy as it seems to maximize error detection.&lt;br /&gt;First of all, specifying test case requires a “destructive” mindset. You should find pleasure in finding errors. This is the right attitude to find as many errors as possible during your programming effort. So this implies that we write imperfect code. This is not always easy to accept for some people but nevertheless a good starting point to begin specifying test case data.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I summed up several techniques that can help you in finding the right set of test cases to find as many as errors as possible. The most important advice we can give you is to use the different methods in combination. Because only when you look at the problem from different angles, you can reasonably find the test cases that will filter out the bulk of the error conditions within the restrictions of budget and resources.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;As you gradually become more familiar with the techniques you will not only come up with effective test cases but you will also think about testing while you’re coding. This will make you think how you can avoid an error condition in your code. Mind though you still will have to write out the test case even if you know your code can handle the situation.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Maybe while looking for test cases will give you more insight into the specifications that lead up to the code you’re investigating, making it more clear what you’re actually programming and how it fits in the whole picture. Maybe you will detect things that were omitted from the specification, either by accident or because the writer felt them to be obvious.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Continuing with this logic of thinking, Test-driven development puts testing completely on the fore-ground. You actually write test before writing any code. In that respect, testing becomes part of your (micro) design process. But that's for another post. &lt;/p&gt;&lt;p&gt;&lt;strong&gt;Sources and further reading&lt;br /&gt;&lt;/strong&gt;&lt;psources&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Test-driven development by example, Kent Beck, Addison-Wesley 2003&lt;/li&gt;&lt;li&gt;The Art of Software Testing, Second Edition, Glenford J. Myers ,John Wiley &amp;amp; Sons 2004&lt;/li&gt;&lt;li&gt;A Practitioner's Guide to Software Test Design, Lee Copeland ,Artech House 2004&lt;/li&gt;&lt;li&gt;BUG TAXONOMY AND STATISTICS, Boris Beizer , &lt;a href="http://inet.uni2.dk/~vinter/bugtaxst.doc"&gt;http://inet.uni2.dk/~vinter/bugtaxst.doc&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Developing and using defect classification schemes, Freimut, B.,http://publica.fraunhofer.de/eprints/N-8167.pdf&lt;/li&gt;&lt;li&gt;Pex ; Dynamic Analysis and Test Generation for .NET, &lt;a href="http://research.microsoft.com/Pex/"&gt;http://research.microsoft.com/Pex/&lt;/a&gt; &lt;/li&gt;&lt;li&gt;Code Coverage Analysis, Steve Cornett, &lt;a href="http://www.bullseye.com/coverage.html"&gt;http://www.bullseye.com/coverage.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;How Do You Know When You Are Done Testing? Richard Bender &lt;a href="http://www.benderrbt.com/Bender-How%20Do%20You%20Know%20When%20You%20Are%20Done%20Testing.pdf"&gt;http://www.benderrbt.com/Bender-How%20Do%20You%20Know%20When%20You%20Are%20Done%20Testing.pdf&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Don't be fooled by the coverage report, Andrew Glover ,http://www-128.ibm.com/developerworks/java/library/j-cq01316/index.html&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-6581209380845185431?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/6581209380845185431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=6581209380845185431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6581209380845185431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/6581209380845185431'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/test-specification-techniques.html' title='Test Specification techniques'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_GROsRPS-U-k/RwSZ1Mpu8BI/AAAAAAAAAFU/592e_UeN3Vc/s72-c/testcasesources.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-744449208180244943</id><published>2007-10-03T10:10:00.000+02:00</published><updated>2007-10-03T10:37:37.218+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Continuous Integration</title><content type='html'>&lt;strong&gt;Early feedback for quality assurance&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Continuous Integration (CI) is a software development practice where members of a team integrate their work frequently; usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. This approach can lead to reduced integration problems and allows a team to develop cohesive software more rapidly.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Build automation&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Just building your application is relatively easy using a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;IDE&lt;/span&gt; : Decide whether you want a debug or a release build, and then select Build Solution or Rebuild Solution from the Build menu in for example Visual Studio .NET (VS .NET). But the manual approach is not sufficient for a project of any reasonable size. If you’re working with other developers, for example, you need to remember to get the latest pieces from your source code control system before building. You might also have unit tests to run through, documentation to update, and so on. The problem with attempting to put all the pieces together by hand is that people tend to forget things. This is where an automated build tool can be helpful with for example &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Nant&lt;/span&gt; or &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;MsBuild&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Continuous integration&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If daily builds are good, then even more frequent builds are better. After all, the sooner you spot a problem in a build, the sooner you can get to work fixing it. The logical extension of this line of reasoning is to rebuild your application every time anyone checks a change into your source code control system. This is where continuous integration (CI) steps in.&lt;br /&gt;&lt;br /&gt;Continuous integration (CI) in that perspective is a technique to ensure the quality a software product during development where all the necessary assets of the product to build an application are under version control.&lt;br /&gt;&lt;br /&gt;In order to integrate CI in your development process you make use of a CI application. This application monitors your source code control repository for check-ins. When it detects an updated file, it gets the current code, instructs to build the project, and look for failures. With instant feedback via e-mail or a web page, it can help you be sure that no one has accidentally checked in untested code.&lt;br /&gt;&lt;br /&gt;Introducing CI is not only a technology implementation but also requires soft skills CI demands a certain discipline of the developer and project/team leaders to make CI give its benefits. The developer may not check in untested code and all the team members must interpret the reports generated by the CI application and do something with it if required (build failure, code complexity, etc.)&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The CI process consists of the following steps:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;SourceControl&lt;/span&gt; system monitoring&lt;/li&gt;&lt;li&gt;Building &lt;/li&gt;&lt;li&gt;Unit testing &lt;/li&gt;&lt;li&gt;Coverage Analysis &lt;/li&gt;&lt;li&gt;Static Code Analysis &lt;/li&gt;&lt;li&gt;Documentation Generation&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These steps (some are optional) are executed by the CI build server every time a modification is detected in the source code. Each of these steps produces data, which is stored in a repository. A project portal is used to present these data items, in various reports.&lt;/p&gt;&lt;p&gt;All &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;artifacts&lt;/span&gt; in order to build a working software product should be put into a source control system like Visual &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;SourceSafe&lt;/span&gt;. The CI process that runs on the build server continuously scans the source control system for changes, and starts the build process as soon as a change is detected. The build server gets the latest version of the code base, and builds the software in one or more configurations. If the build fails, the build process is aborted and the build is considered to be broken. A broken build is a serious situation within CI, which should be remedied as soon as possible.&lt;br /&gt;&lt;br /&gt;If the build succeeds, the other CI steps will be performed and eventually the build output will be copied to a drop location.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Unit testing and Code coverage analysis&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;The CI environment will run a set of specified unit test on the build server, each time integration of new functionality takes place. During these unit tests, code coverage is measured and registered by the build server. Code coverage provides developers and testers with information about what code is touched when a test is run. The results of the unit tests and the coverage analysis metrics are published on the project portal.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Static Code Analysis and Code metrics&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Static code analysis checks code for conformance to the Design Guidelines and/or naming guidelines. The CI environment can perform Static Code Analysis on the build server, every time new functionality has been checked in to source control. A software metric is a measure of some property of a piece of software or its specifications. Tools can gather some code metrics on basis of the source code. These metrics can be used to track some aspects of your code that can influence some software quality aspects : maintainability, readability, etc.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;a name="_Toc171475701"&gt;&lt;strong&gt;Documentation Generation&lt;/strong&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The CI environment can automatically generate documentation during the build process. This is usually technical documentation that describes the internal structure of the application, such as classes and data structures. For example &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;Ndoc&lt;/span&gt; or &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;DoxyGen&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;CI output&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;The CI environment will publish all the outcomes of the different &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;workflows&lt;/span&gt; on a portal and can inform interested parties about the build outcome.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;So the main purpose of CI is the early detection of integration issues and furthermore is quality improvement measure. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;CI can help you measure &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;cyclomatic&lt;/span&gt; complexity, code duplication, dependencies and coding standards so that developers can proactively &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;refactor&lt;/span&gt; code before a defect is introduced. &lt;/li&gt;&lt;li&gt;If a defect is introduced into a code base, CI can provide feedback soon after, when defects are less complex and less expensive to fix. &lt;/li&gt;&lt;li&gt;CI provides quick feedback, via regression tests, on software that was previously working and is adversely affected by a new change.&lt;/li&gt;&lt;/ul&gt;But you need to understand that CI is more than a technology. It requires some &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_11"&gt;discipline&lt;/span&gt; from the developers and involvement of project management. Running CI without doing something with the information will not improve the quality of your software application. Meaning that somebody has to watch the builds and care when they are broken. Furthermore the developer must "fix" any broken CI builds.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Sources and recommened reading&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Continuous Integration, Martin Fowler  &lt;a href="http://www.martinfowler.com/articles/continuousIntegration.html"&gt;http://www.martinfowler.com/articles/continuousIntegration.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Coder to Developer: Tools and Strategies for Delivering Your Software  Mike Gunderloy  Sybex 2004 ISBN 078214327X&lt;/li&gt;&lt;li&gt;Expert .NET Delivery Using NAnt and CruiseControl.NET, by Marc Holmes  Apress  2005&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-744449208180244943?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/744449208180244943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=744449208180244943' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/744449208180244943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/744449208180244943'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/continuous-integration.html' title='Continuous Integration'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-8648746876202456877</id><published>2007-10-03T09:53:00.000+02:00</published><updated>2007-10-03T10:06:15.745+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Development Organisation'/><title type='text'>Software factory</title><content type='html'>&lt;strong&gt;Reuse of people,process and technology&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;A software factory is an approach to build applications with more or less the same structural characteristics through the use of more or less fixed combination of skilled people on the various topics within software development, processes and technology.  So you say that software factories is a form of reuse. Not only "code", but also processes and people.&lt;br /&gt;&lt;br /&gt;With a high degree of “industrialization”, it is seeking the maximum efficiency &amp;amp; productivity through:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Processes Standardization for project management and software development &lt;/li&gt;&lt;li&gt;Re-utilization &amp;amp; use of frameworks&lt;/li&gt;&lt;li&gt;Automation &amp;amp; tools &lt;/li&gt;&lt;li&gt;Skilled professionals&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;With these strategies it wants to reduce the development cycles (“Time to Market”) and the total cost of the project while keeping a high degree of quality for the complete cycle.&lt;br /&gt;So if you have lot applications that share same structural characteristics such the development language, code organisation, and usage of third party libraries you can think about creating such a generic software Creation platform. I will be reused for all the concerned applications. More over you will be encouraged to let your future application share as much characteristics as possible. The more standardized to more benefit you’ll gain from re-use.&lt;br /&gt;&lt;br /&gt;Usually Software factories are organized around a broad technology platform like .NET, JAVA, or SAP&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Factory metaphor limitations&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;As with all metaphors you must not drive them to far else you’ll end up creating false expectations. Creating software is not the same as making cars or radios where predefined parts are assembled together while moving from one point in the factory to another until they are completed, checked and shipped. Software is not a mass-production item.  It is not even tangible. More over, software is never finished. It build adjusted, expanded, reshaped throughout it life-time. Even during “assembly” the shape of the “product” is completely written in stone.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Microsoft definition of Software factories&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Microsoft also uses the term software factories but it is not used to describe the assembly-line idea. They use it to name several Development accelerators packages. It frees the developer of creating something from scratch. The packages are materialized in the form of Visual Studio wizards, templates, project structures, components, frameworks but also best practices in the form of white papers.&lt;br /&gt;De developer working with such a software factory in Visual studio will see the structure of the project so that the developer knows exactly which things to complete; which deliverables he has to work on; which are fixed for him, because they represent the architecture of that application.&lt;br /&gt;So this definition does not emphasis on people and processes that much but rather on automation (technology).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6998972826668184815-8648746876202456877?l=appdevchronicles.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://appdevchronicles.blogspot.com/feeds/8648746876202456877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6998972826668184815&amp;postID=8648746876202456877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8648746876202456877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6998972826668184815/posts/default/8648746876202456877'/><link rel='alternate' type='text/html' href='http://appdevchronicles.blogspot.com/2007/10/software-factory.html' title='Software factory'/><author><name>anowak</name><uri>http://www.blogger.com/profile/07263503071418512056</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6998972826668184815.post-8081364755994842755</id><published>2007-10-03T09:40:00.000+02:00</published><updated>2007-10-03T09:49:21.972+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Testing'/><title type='text'>Making unit tests</title><content type='html'>&lt;p&gt;What approach should you take in setting up unit tests?&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A more pragmatic approach where tests are more API usage-oriented, how you expected other parts of your application to interact with your unit of code. &lt;/li&gt;&lt;li&gt;Or should you strive for a formal way of working where systematically check every each method for all boundary conditions and error paths. &lt;/li&gt;&lt;li&gt;Or should you use both? &lt;/li&gt;&lt;li&gt;What approach in which conditions? &lt;/li&gt;&lt;li&gt;Should conduct a test-first approach, or test after approach? Or should you write your test during?&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Take a look at this sample method:&lt;br /&gt;&lt;br /&gt;'Method returns true if the person is over age 18, otherwise false&lt;br /&gt;Public Function AgeCheck(dob as Date) as Boolean&lt;br /&gt;'Some processing code here…&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The premise of this code is fairly straightforward. It accepts a date of birth and validates the age. At first glance, you may think that you simply need to run a test that provides a date of birth prior to 18 years ago and a date of birth later than 18 years ago. And that works great for 80% of the dates that someone is likely to provide, but that only scratches the surface of what could be tested here. The following are some of the tests you may also consider to run for the AgeCheck method:&lt;br /&gt;&lt;br /&gt;• Check a date from exactly 18 years ago to the day.&lt;br /&gt;• Check a date from further back in time than 18 years.&lt;br /&gt;• Check a date from fewer than 18 years ago.&lt;br /&gt;• Check for the results based on the very minimum date that can be entered.&lt;br /&gt;• Check for the results based on the very maximum date that can be entered.&lt;br /&gt;• Check for an invalid date format being passed to the method.&lt;br /&gt;• Check two year dates (such as 05/05/49) to determine what century the two-year format is being treated as.&lt;br /&gt;• Check the time (if that matters) of the date.&lt;br /&gt;&lt;br /&gt;As you can see, based on just a simple method declaration, you can determine at least 5 and maybe as many as 10 valid unit tests (not all tests may be required).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;These following areas cover the majority of the situations you will run into when performing unit tests. Any approach should take into account tests that cover these areas of potential failure. Of course, this is by no means a comprehensive set of rules for unit testing. There will undoubtedly be others related to specific applications.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Boundary values&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Testing the minimum and maximum values allowed for a given parameter. An example here is when dealing with strings. What happens if you are passed an empty string? Is it valid? On the other hand, what if som
