• The Emergent Method

    Like last post, i'm trolling the tech ed videos. i wasn't so lucky that i actually got to go this year, but i'm glad that other people got to. Not that they need to more than I but that i'm glad they did and brought back an energy level for some new ideas.

    I started watching Juval Lowy on 'The zen of architecture'
    Get Microsoft Silverlight
     ... now i am not a BDUF kind of guy. I'm more of an emergent design type of guy. So when he said spend a couple of weeks to look at 'all' of the use cases I laughed a little bit to myself. There is no such thing as 'all of the use cases'... i think it is the same type of assumption that the requirements are out there you just have to 'capture them'. Some would say there is no such thing as a requirement because everything is negotiable.

    Anyhow... here's what I took away:
    1. use very light weight diagrams that are simple to understand
    2. use the 'transaction script pattern' from Martin Fowler's Patterns of Enterprise Architecture
    3. make every object a service (when appropriate, at least at entry point to layer boundaries) because it promotes isolation and a bunch of other good stuff.
    4. Why layers are important and some guidelines/starting points
    Here's what I would expand on for us agilists...for sprint 1 or sprint 0 if you believe in it.
    1. Build from the front to the back: Client first, then manager to create the stubbed in use case to identify the data.
    2. Choose a couple of user stories that have the most reason for volatility. For example if you are writing an application that does debit card authorizations... what about paypal authorizations or credit card authorizations in the future? Each of those types of authorizations is a variant of the authorization engine.
    3. Include user stories that will have a variety of authorization and authentication at different layers.
    4. choose a story that goes all the way through the architecture. a bad choice would be a javascript animation. 
    5. the amount of time spent should be scaled back to 2-3 days. Obviously negotiable just don't let it turn into a full design phase. 
    Instead of diagramming every single use case i would just diagram the first couple of user stories that you think might have the potential to meet the above criteria. For example, I was writing an advertising campaign system and my first user story was one that calculated the rules on whether to show the customer an ad based on their number of logins. It was 1 rule out of many, it hit all the major architectural pieces (web, app, data tiers) and it gave the customer something they could look at right away and expand on.

    So do a couple of use cases until you find the right ones and give everyone a feel for the big picture. do the design together with everyone... not just alone as the architect. Get the knowledge transferred to the team. 

     Ok now throw away the diagrams. They'll only cause confusion later on. 

    As an example, i had a customer contact me and ask me a few questions about what our software did in a certain scenario... the business analyst said ok i think i have thata documentation (the PRD). I said "i'll go check the code". She came back with the document and explained what it said... i read the code and explained that she was wrong. She actually argued with me on it...
    This is code that was developed and had been in production for years now... i'm pretty sure the code is right and the documentation is wrong.

    Point is here... you can make all of these diagrams and communicate a good vision for your product but the only lasting documentation of the project should be the unit tests and the code itself. Everything else is just an intermediate work item and is waste. Keeping it around can often only lead to confusion and misinterpretation. 

    If you do have to keep it around for any regulatory reason, just be sure to go double check yourself against the real code.

    Anyhow enough harping on documentation (i clearly have issues with it being misused).

    Frankly my rant on compliance and audits: I don't see why an intermediate piece of documentation needs to be kept around since code itself is a document... but that's another fight for another day. I would argue that the code is just as easy to read as the cryptic jargon they put in PRDs and it's WAY less ambiguous. in fact, it's never ambiguous, it does exactly what it says it does.

    Full story

    Comments (0)

  • Top 10 mistakes in unit testing

    Finally got around to watching this presentation.

    http://www.msteched.com/2010/NorthAmerica/DPR204

    Thanks Shawn! it was good stuff.

    Like Ben Day, i also program that way... it's very tough to try to program that way in a legacy program though. Which, i think every one of our programs is 'legacy' by the Michael Feathers definition. "code without tests"

    I would add legacy code to me it is

    "code without automated unit tests that give me rapid feedback."

    I will further clarify:

    "Legacy" is code that can not be tested and verified within 5minutes that all previous components still work in the same manner after my changes.

    I say that because a unit test can be interpreted in many ways... but you cannot misinterpet the ability to fully regression test your code and detect breaking changes within 5 minutes.

    and 5 minutes is a bit arbitrary... but the number is to mean "the maximum amount of time that the team will tolerate to run the test suite after every reasonable change"

    and by reasonable i mean... if you write some new functionality that completes a goal then run the regression suite. If you're just writing a component class/method then just run the test harness for that functionality (runs very quickly).

     

    So i feel like i'm rambling a bit but i've been really trying to stick to TDD in my code. I haven't really been able to achieve the structure that i would like... or the organization... i'm still struggling with finding the right folder locations and assembly organization.

    That being said things are moving along nicely towards TDD bliss.

    Next step is probably to figure out a IoC container... we already can use unity so i'll probably choose that out of laziness. I really love NInject the most though. Maybe once we're solidly on .net 3.5 i can use it.

    One thing that i've also struggled with is dependencies... we have a 3 tiered application and each tier is impossible to contain in a unit test. So i generally have MVP with a service dependency, logging dependency(yea i know i should use AOP), configuration dependency, and view dependency injected into the presenter. It starts to get pretty hairy!!!

     

    public class MyExamplePresenter

    {

        MyExamplePresenter(IExampleView view, IExampleConfigurationRepository config, IExampleBusinessLogicService service, IExampleBusinessLogicService2 service2)

        {

     

    Paraphrased of course... but sometimes the param list gets a bit long. maybe it's time to make a facade pattern interface for the BLL services? :)

     

    TBD!

     

     

     

     

    Full story

    Comments (0)

  • Back From Training Syndrome

    Lately I've had some luck capitalizing on people's energy after having some training. I think it was good that they've all been going to training and events around the same time frame because it's easier to push a boulder up hill with 5 people than only 1.

    If you're pressing for agile practices or trying to encourage a shift in thinking PLEASE try this advice:

    1. get everyone to agree on at least a similiar type of training. TDD or Scrum for example
    2. if possible send everyone at the same time so they all have the same frame of reference and they can all push together
    3. when they get back encourage them to try what they've learned and pick specific places to use it
    4. help remove any roadblocks to their experiments
      1. remove work if necessary until a steady pace or the new practices take hold
      2. block interruptions to their learning process to let them solidify their new skills at work

    Training is good if you can capitalize on the result of it otherwise people will move on to somewhere that they can use those skills. Don't become that company that trains people for other companies.

     

    Full story

    Comments (0)

  • Is Ninject 2 Stealthy

    Based on this documentation for Ninject , they claim to be stealthy!

     

    Stating:

    Ninject will not invade your code. You can easily isolate the dependency on Ninject to a single assembly in your project.”

     

    Well, at first I was skeptical and just could not figure it out. So I put on my scientist hat for a little while in an attempt to prove them right!

     

    Here’s what my test bed looked like… a pretty standard project configuration with multiple DLLs

     

      

     

     

    1. A console application. My driver program.
    2. A contracts DLL. My abstracts and interfaces that are known to the driver program.
    3. A service locator DLL. My services and Factories that will provide my driver program and class libraries everything they need.
    4. My first class library dll. This is where I would usually put some type of layered architecture or group of assemblies for a new release.
    5. My second class library dll. This is the same as above but separate from the previous one. 

     

       Now here are the references:  

     

    1, 4, and 5 reference 2 and 3. (and every dll you ever make after this would reference 2 and 3)

    3 references 4 and 5 (and any new dlls you ever make) 

     

    Here’s the layout of where all the type definitions are so you can visualize it:

     

     

     

    Here’s the driver program code. The test bed for this little experiment: 

    using System;

    using IsolatingTheNinja.Contracts;

    using IsolatingTheNinja.Services;

     

    namespace IsolatingTheNinja

    {

        class Program 

        {

            static void Main(string[] args)

            {

                ILibrary1Type type1Instance = ServiceLocator.CreateLibrary1Type();

                ILibrary2Type type2Instance = ServiceLocator.CreateLibrary2Type();

     

                Console.WriteLine(type1Instance);

                Console.WriteLine(type2Instance);

                Console.WriteLine("Press any key to exit");

                Console.ReadKey();

            }

        }

    } 

      

     

    Here’s my Service Locator implementation:

    using IsolatingTheNinja.Contracts;

    using Ninject;

    using Ninject.Modules;

     

    namespace IsolatingTheNinja.Services

    {

        public class ServiceLocator 

        {

            private static readonly IKernel _kernel = new StandardKernel(new INinjectModule[] { new Library1Module(), new

    Library2Module() });

     

            public static ILibrary1Type CreateLibrary1Type()

            {

                return _kernel.Get<ILibrary1Type>();

            }

            public static ILibrary2Type CreateLibrary2Type()

            {

                return _kernel.Get<ILibrary2Type>();

            }

        }

    }

      

     

    Here’s an example of my module:

    using IsolatingTheNinja.Contracts;

    using IsolatingTheNinja.Library1;

    using Ninject.Modules;

     

    namespace IsolatingTheNinja.Services

    {

        public class Library1Module : NinjectModule 

        {

            public override void Load()

            {

                Bind<ILibrary1Type>().To<Library1Type>();

            }

        }

    }

     

    The end result: SUCCESS. Ninject IS Stealthy! 

     Here’s the Source code

     

     

     

     

     

     

     

     

     

     

     

    Full story

    Comments (0)

  • Setting Up Fitnesse for C# .Net

    I use to use cory foy's example, but it's a bit dated now.

     

    Step 1:

    Download fitnesse

    http://fitnesse.org/FrontPage.FitNesseDevelopment.DownLoad

     

    click the fitnesse.jar link

     

    extract it to c:\fitnesse

     

    run java –jar fitnesse.jar –p [port]

    (If you want port 80 then leave off the –p and port)

     

    Navigate to http://localhost/ to try it out or http://localhost:[port]

     

    Step 2:

    Get fitsharp so you have the dlls for making fixtures and slim runner

    go to: http://github.com/jediwhale/fitsharp/downloads

    extract it to c:\fitnesse\slim

     

    Step 3:

    Make your test fixtures class library in visual studio

     

    Step 4:

    reference the fit and fitsharp dlls from c:\fitnesse\slim

    and reference any of your “System under test” dlls. (your dlls that your system uses that you want to test)

     

    Step 5:

    Write a fixture

    using fit;

     

    namespace Fitnesse

    {

        public class CalculateDiscount : ColumnFixture

        {

        }

    }

     

    Step 6:

    Make your first wiki page.

    Such as editing the front page and adding MyFirstFitnessePage

    It will show up like this after you save it:

    MyFirstFitnessePage?

    Click on the ‘?’ to create it.

     

    Step 7: make it a test page

    go to properties and change it to a “test” page.

     

    Step 8: Add all this stuff to the top of it

    !define TEST_SYSTEM {slim}

    !define COMMAND_PATTERN {%m -r

    fitSharp.Slim.Service.Runner,C:\Fitnesse\slim\fitsharp.dll %p}

    !define TEST_RUNNER {C:\Fitnesse\slim\Runner.exe}

    !path C:\projects\Fitnesse\Fitnesse\bin\Debug\Fitnesse.dll

     

    (the last line should be a direct path to your fixtures dll)

     

    Step 9:

    Make a test table

    |!-Fitnesse.CalculateDiscount-!|

    |amount     |discount?    |

    |0          |0             |

    |100        |0             |

    |999        |0             |

    |1000       |0             |

    |1010       |50.5          |

    |1100       |55            |

    |1200       |60            |

    |2000       |1000          |

     

    the !- -! Syntax forces literal text so it won’t interpret “CalculateDiscount” as a wiki page link you’ll get an error like this if you don’t do it

     

    Could not find class CalculateDiscountATitleCreatePageHrefCalculateDiscountEditNonExistentTrueA

     

    Apparently “ATitleCreatePageHrefCalculateDiscountEditNonExistentTrueA” gets appended when the ? is next to it.

     

     

     

    Full story

    Comments (0)

  • NHibernate basic 2 table example

    I’m slowly becoming intrigued by NHibernate and was playing around with it against AdventureWorks tonight.

     

    I came up with this basic 2 table tutorial using Employee and Contact.

     

    First, I created a wpf project for my user interface and I slapped a ListView on the main window like this:

    <Window x:Class="NHAdventureWorks.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Window1" Height="300" Width="300"

         Loaded="Window_Loaded">

        <Grid>

            <ListView x:Name="lvwEmployees">

                

            </ListView>

        </Grid>

    </Window>

     

    Then I hooked up the Loaded Event:

    private void Window_Loaded(object sender, RoutedEventArgs e)

            {

                this.lvwEmployees.ItemsSource = LoadEmployeesFromDatabase();

            }

     

    Then I added this code from the ‘hello world’ example in Manning’s “NHibernate in action” book:

            static ISession OpenSession()

            {

                if (factory == null)

                {

                    Configuration c = new Configuration();

                    //c.AddClass(typeof(Employee));

                    c.AddAssembly(Assembly.GetCallingAssembly());

                    factory = c.BuildSessionFactory();

                }

                return factory.OpenSession();

            }

            static ISessionFactory factory;

     

            static IList<Employee> LoadEmployeesFromDatabase()

            {

                using (ISession session = OpenSession())

                {

                    IQuery query = session.CreateQuery(

                    "from Employee as emp order by emp.Contact.LastName asc");

                    IList<Employee> foundEmployees = query.List<Employee>();

                    return foundEmployees;

                }

            }

     

    Then I declared my domain model classes Employee and Contact as such:

        internal class Employee

        {

            internal int EmployeeId;

            internal string LoginId;

            internal Contact Contact { get; set; }

            internal int ContactId;

            public override string ToString()

            {

                return string.Format("{0} : {1} {2}", LoginId, Contact.FirstName, Contact.LastName);

            }

     

        }

        internal class Contact

        {

            internal int ContactId;

            internal string FirstName;

            internal string LastName;

     

        }

     

    Then I had to do the NHibernate specific stuff. First I added an xml file to the project called Employee.hbm.xml and then changed it’s build action to “Embedded Resource” (VERY IMPORTANT)

    Then I added a Contact.hbm.xml file as well (also marked as Embedded Resource). Then their contents looked like this respectively:

     

    <?xml version="1.0"?>

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

    auto-import="true">

      <class name="NHAdventureWorks.Employee, NHAdventureWorks"

             table="HumanResources.Employee" lazy="false">

        <id name="EmployeeId"

            column="EmployeeID"

            access="field">

          <generator class="native" />

        </id>

        <property name="LoginId" access="field" column="LoginID"/>

        <many-to-one

          name="Contact"

          column="ContactID"

          class="NHAdventureWorks.Contact, NHAdventureWorks"

          not-null="true" />

      </class>

    </hibernate-mapping>

     

    <?xml version="1.0"?>

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

    auto-import="true">

      <class name="NHAdventureWorks.Contact, NHAdventureWorks"

             table="Person.Contact"

             lazy="false">

        <id name="ContactId"

           column="ContactID"

           access="field">

          <generator class="native" />

        </id>

        <property name="FirstName" access="field" column="FirstName"/>

        <property name="LastName" access="field" column="LastName"/>

      </class>

    </hibernate-mapping>

     

    Of course there are some app.config settings that had to be put into place:

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <configSections>

        <section name="hibernate-configuration"

                 type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />

        <section name="log4net"

                 type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

      </configSections>

      <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">

        <session-factory>

          <property name="connection.provider">

            NHibernate.Connection.DriverConnectionProvider

          </property>

          <property name="connection.driver_class">

            NHibernate.Driver.SqlClientDriver

          </property>

          <property name="connection.connection_string">

            Server=(local);database=AdventureWorks;Integrated Security=SSPI;

          </property>

          <property name="dialect">

            NHibernate.Dialect.MsSql2000Dialect

          </property>

          <property name="show_sql">

            false

          </property>

          <property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>

        </session-factory>

      </hibernate-configuration>

      <log4net>

        <appender name="ConsoleAppender"

        type="log4net.Appender.ConsoleAppender, log4net">

          <layout type="log4net.Layout.PatternLayout, log4net">

            <param name="ConversionPattern" value="%m" />

          </layout>

        </appender>

        <root>

          <priority value="WARN" />

          <appender-ref ref="ConsoleAppender" />

        </root>

      </log4net>

    </configuration>

    Full story

    Comments (0)

  • Scrum Starting Practices: Sprint Planning

    This may or may not be helpful to some people but i just wanted to do a walk-through of a typical sprint planning 'process' I just tried using with the current team I'm on. We have me (programmer/scrum master), a tester, a business person, a requirement writer, and various 'specialists' giving us hours here and there (mainframe, webservices, and database). I'm basically acting as scrum master and sometimes as 'product owner' in many regards. (generally the product owner situations i end up in are ones where the technical team must prioritize and the customer team does not care one way or another on the priority at that low of level)

    1. I fire up Breeze (it's basically like a Webex or typical desktop sharing utility)
    2. I get everyone connected so they can see my desktop.
    3. I launch scrumworks (our chosen tool for distributed scrum) - maybe you use a spreadsheet or story cards or whatever.
    4. I load up our PRD (product requirements document) for a particular project (usually to add to our existing 'evergreen' product)
    5. I read the first "Detailed Business Requirement" outloud or ask the team to read it on the their own. (usually they have their own copy of the word document.
    6. Create a backlog item in scrumworks that represents that requirement.
    7. Have a timeboxed discussion (i usually don't set a time limit because people already have a tough time speaking up, but if it goes on too long in silence i start asking specific people questions... like 'if you had this software in front of you and you were going to validate this requirement, what would you do?)
    8. Ask the QA people what they would plan on testing. Maybe ask the business what QA might have missed or vice versa.
    9. break down the feature/backlog item into tasks. In scrumworks i usually denote each task with a functional group and then the task. for example the backlog item might be "User can save their settings". The tasks would maybe be "Dev: build aspx page layout", "Dev: build model classes", "Dba: setup tables and sprocs", "QA: write test scripts", "QA: execute test scripts" "BIZ: user acceptance test"
    10. Once the tasks have been decomposed and estimated in 'ideal hours' i total that up and assign the backlog item that as the 'ideal hour' size. Yes most tasks can run concurrently but the point is getting a general 'complexity' or 'size' to it so i figure there's a bit of shwag to it anyhow.
    11. Ask the team if they have enough room to commit to this backlog item taking into consideration all the functional groups needed to get to "Done" on it.
    12. Add it to the Sprint or skip it depending on 10
    13. Repeat steps 5-12 as needed until no more backlog items can be committed to.
    14. Some requirements may need consolidated into one backlog item (for example if a requirement is Dependant on another, I put them together as one and see if it makes sense... sometimes then we split them back out if it makes sense to split them in a different way by 'features' instead of by layers of software)
    15. Revisit estimates on the next reasonable amount of backlog items or estimate any un-estimated backlog items in the product backlog.

    Full story

    Comments (0)

  • Why is my scrum team not reporting impediments?

    5 little things I have done to lose the scrum team’s trust

     

    1. Turned responsibility back solely on the individual reporting the impediment.
    2. Tell them that it’s ‘just the way things work’ at this company or otherwise keep status quo
    3. Lose track of open impediments. Fall through the cracks.
    4. Assign someone different work when they’re impeded
    5. Embarrass them for silly questions or use “but” language in front of peers.

     

    Things we can do to get people to report all impediments

    1. Take every single impediment seriously
    2. be genuinely concerned and interested. Note your body language.
    3. Write it down somewhere visible.
    4. Make the solution to every impediment clearly visible to the whole team
    5. Take personal responsibility to ‘facilitate’ a solution with ‘team accountability’
    6. Thank them for reporting the issue

    Full story

    Comments (0)

  • Making a custom mouse cursor in silverlight 3

    When you write games in silverlight you are going to want to make a custom mouse cursor. Maybe you want a gun cross hair or maybe an animated cursor of some sort. I’ve found no way to do this other than to turn off the cursor and hook an image up to the mouse move events.

     

    Basically let’s start with a silverlight application and change the Grid to a Canvas like this:

    <UserControl x:Class="MouseCursorReplacement.MainPage"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

        <Canvas x:Name="LayoutRoot">

           

        </Canvas>

    </UserControl>

     

    Now add a cursor representation as an image tag and point it to your new cursor file. In this case I’m using a cross hair. I make the ZIndex high so it floats on top of anything I put in.

    <UserControl x:Class="MouseCursorReplacement.MainPage"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

        <Canvas x:Name="LayoutRoot">

            <Image x:Name="CustomCursorImage" Source="cross.png" Canvas.ZIndex="100"/>

        </Canvas>

    </UserControl>

     

    Now go into your code behind and setup a load event and disable the cursor:

        public partial class MainPage : UserControl

        {

            public MainPage()

            {

                this.Loaded += new RoutedEventHandler(MainPage_Loaded);

                InitializeComponent();

            }

     

            void MainPage_Loaded(object sender, RoutedEventArgs e)

            {

                this.Cursor = Cursors.None;

            }

        }

     

    Now add a mouse move event and finally the code that will make the image move around as your new cursor.

            public MainPage()

            {

                this.Loaded += new RoutedEventHandler(MainPage_Loaded);

                this.MouseMove += new MouseEventHandler(MainPage_MouseMove);

                InitializeComponent();

            }

     

            void MainPage_MouseMove(object sender, MouseEventArgs e)

            {

                Point position = e.GetPosition(LayoutRoot);

                double leftOffset = CustomCursorImage.ActualWidth / 2;

                double topOffset = CustomCursorImage.ActualHeight / 2;

                double newLeft = position.X - leftOffset;

                double newTop = position.Y - topOffset;

                Canvas.SetLeft(CustomCursorImage, newLeft);

                Canvas.SetTop(CustomCursorImage, newTop);

            }

     

    The last part. And I find this a little ‘magical’ is that when the background was white the mouse kept “losing” the new cursor. So I changed the background to classic ‘directx’ cornflowerblue and the problem went away (I don’t know why and believe me I don’t usually fall for the ‘it must be magic’ comment, but apparently it works?):

     

    <UserControl x:Class="MouseCursorReplacement.MainPage"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

        <Canvas x:Name="LayoutRoot" Background="CornflowerBlue">

            <Image x:Name="CustomCursorImage" Source="cross.png" Canvas.ZIndex="100"/>

        </Canvas>

    </UserControl>

     

     

    Full story

    Comments (0)

  • Some TDD in the real world

    One of the most common things that I run into when doing TDD with NUnit in the 'real world' is that the ugly truth is dependencies are either hard or impossible to test.

     

    Take for example this code snippet where we're calling a webservice a couple times to do some work.

        public class HumanResources

     

        {

            public void FireThisGuy(long employeeId)

            {

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                Employee emp = service.GetEmployee(request).Employee;

                emp.TerminationDate = DateTime.Now;

     

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

        }

     

     

     

     

     

    We know it's a bad practice to call webservices in our unit tests for a few reasons. (namely it's slow). So let's refactor a little and remove anything related to the webservices out. I extract method on the get...

           public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

     

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

     

    notice this wasn't a straight up 'extract to method' on your refactoring tool. I did about 5 small refactorings before i did the extract but just notice the complete extraction of the dependency on the webservice to a new method "GetEmployeeById".

     

    now the same for the set:

     

           public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

                SetEmployee(emp);

            }

     

            protected void SetEmployee(Employee emp)

            {

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

     

    now for my unit test the only thing i really want to test is the "FireThisGuy" logic. so first i would need to inherit from HumanResources and make a testing class that overrides the 2 dependencies i do not want.

        public class HumanResources

        {

            public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

                SetEmployee(emp);

            }

     

            protected virtual void SetEmployee(Employee emp)

            {

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected virtual Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

        }

        public class TestingHumanResources : HumanResources

        {

            public Employee GetEmployeeByIdTestingEmployee { get; set; }

            protected override Employee GetEmployeeById(long employeeId)

            {

                return GetEmployeeByIdTestingEmployee;

            }

     

            public Employee SetTestingEmployee { get; set; }

            protected override void SetEmployee(Employee emp)

            {

                SetTestingEmployee = emp;

            }

        }

     

     

     

     

     

     

     

     

     

    Now i can actually write a test that validates

      public class HumanResources

        {

            public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

                SetEmployee(emp);

            }

     

            protected virtual void SetEmployee(Employee emp)

            {

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected virtual Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

        }

        public class TestingHumanResources : HumanResources

        {

            public Employee GetEmployeeByIdTestingEmployee { get; set; }

            protected override Employee GetEmployeeById(long employeeId)

            {

                return GetEmployeeByIdTestingEmployee;

            }

     

            public Employee SetTestingEmployee { get; set; }

            protected override void SetEmployee(Employee emp)

            {

                SetTestingEmployee = emp;

            }

        }

        [TestFixture]

        public class HumanResourcesTests

        {

            [Test]

            public void FireThisGuy_UserIdIn_FiredEmployeeSaved()

            {

                TestingHumanResources hr = new TestingHumanResources();

                hr.GetEmployeeByIdTestingEmployee = new Employee();

                hr.GetEmployeeByIdTestingEmployee.TerminationDate = null;

     

                hr.FireThisGuy(200);

                Assert.IsNotNull(hr.SetTestingEmployee.TerminationDate);

     

            }

        }

     

     

     

     

     

     

     

     

     

     

     

     

     

    This is why im a big fan of object oriented programming and using inheritance to break dependencies. It's a real fast solution to some of the unique dependency issues i fight every day and it is a lot easier to read and debug than tons of interfaces.  This and other examples of seaming and seperation can be found in Michael Feather's book "Working Effectively with Legacy Code"

     

     

     

     

    Grab the code here

    Full story

    Comments (10)

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. Next page