Friday, August 17, 2012

Fail Safe Test Driven Development

 

Terms

Dependencies – Anything outside of your code.  Database, files, web services,

Dependency Injection framework – framework to help you manage which concrete dependency to use based on a given context.  Example, use mock of ISqlRepo when testing but use real Sql2008Repo when not testing.

Testing Framework – usually has a test runner to run the tests and display the results of each test.  Usually has code framework to create assertions.  eg. Assert.IsTrue( 4 = 2 + 2);

Inversion of control – where you allow the calling method to have a say in how something is done.  saveUser(user, dao)    vs.  saveUser(user)

Mocking – Since you cannot new up an interface, a mocking framework will allow you to create a concrete object from an interface, or override existing functionality in a concrete class.  There are many fun things you can do with mocks like make them observable.  Then you can assert that a certain method is only called a certain number of times.  This can be surprisingly helpful.

Composability – think buffet, you can pick and choose.  Developer has a high degree of control.  vs. happy meal.

Test Friction – how hard is it for you to test your app

Repository Pattern – in short – new up an data model object for you with data.  If your data models are POCO objects, your repo get data from database or other and returns them to the app.

POCO/POPO – Plain Old C Object, Plain old PHP object – object with fields or properties no methods, save maybe getters and setters.

Smurf Naming Convention – When all the classes start with the same thing but add the action eg, CustomerOrderService, CustomerOrderRepo, ICustomerOrder, CustomerOrderDataModel


Tools

  • Language that supports TDD
    • HTML and CSS are not programming languages – limited ability to test
    • SQL is not a programming language – not easily suitable for TDD
  • Testing Framework
  • Mocking Framework
  • Dependency Injection Framework
You do not need a database, file system, browser, web server, version control system.  You should have version control, but you do not need one that supports testing to do TDD.

Philosophy

  • Highly maintainable
  • Low test friction
  • Inversion of Control
  • Loose coupling (not independence) 
  • Composability
  • Helping yourself and others
  • TDD is NOT about customer satisfaction or satisfying product requirements
  • TDD is about embracing the power of the native programming language, not reducing it to one line of code or hiding it.
  • Protect your code from dependencies
  • Avoid the temptation for integration testing – you will fail
  • Be prepared to work around what you cannot test.

Layers

The layers in an app are highly dependent on the app and the goals of the app. You may need each layer to be portable for other projects. On they can just be folders in your existing project.

  • Data Models
  • Application Interface
  • Repo Interface
  • Business Logic – no dependencies 100% your language and under test
  • Application – this is where the layers come together in a loosely coupled fashion to create your app. Your app is just a composition of each of the layers.
  • Tests – not really a layer but should be part of your solution but not part of your application.

Rules

  • Static methods are bad
  • Private methods are bad
  • Starting with tests is important if you want the tests to drive the development 
  • Public methods are good
  • Interfaces are good – how you can control the supported footprint (vs. private methods)
  • Repository Pattern is your friend
  • In MVC skinny models and fat controllers
  • Use constructors to set your dependencies
  • Layers – this requires some practice and discipline
    • Tests should never reach into the application layers
    • Data Models have zero dependencies except the language (PHP, C#, Java)
    • Interfaces have one dependency: Data Models
    • Business Logic – one dependency:  data models (sometimes interfaces)
    • Repository – data models, and any database libraries, cannot reach into the application.
    • Application Logic – Data Models, Interfaces, Business Logic, Repository, Dependency Injection Framework, and many more.  This is where the composition happens.

Workflow

  1. Create a sunny day interface test
  2. Create Data Models (POCO)
  3. Create Interface for repo or service – all depends on what you are building
  4. Use interface to create a mock object that you can test.

After you have a working test, start working backwards, start working on an implementation from the interface.  Create a new test, exactly as your mock but return your implementation not your interface.

Sample

https://github.com/dominionenterprises/FailSafeTDD

Saturday, June 4, 2011

Tweener lists

 <style type="text/css">
  
        ul 
        {
            list-style-typenone;
            line-height2em;
        }
    
        li label     
        {
         
            color#a0a0a0;    
            font-weightbold;    
            background-color:White ;    
            border-stylesolid;
            border-width1px;
            border-color#a0a0a0;
            padding-left:10px;
            padding-right:10px;
            padding-top:3px;
            padding-bottom:3px;
            margin-right:10px;
            font-size12px;
            }
  
  li label:hover {    font-weightbold;    color#FFFFFF;    background-color#999999;    border-styleoutset;}
   
    </style>
</head>
<body>
<input id="PersonIdTextBox" value="123" type="hidden" />
<input id="addSomething" title="add" type="button" value="add" />
 
<div >
  <ul class="divisions">
   <li data-personid="10" data-somethingid="20">
    <label class="removeSomething">remove</label>
    Something 1
   </li>
      <li data-personid="200" data-somethingid=200">
    <label class="removeSomething">remove</label>
    Something 2
   </li>
          </ul>
    </div>
     <script type="text/javascript">
        
 
 
         $("#addSomething").click(function () {
             var personId = $("#PersonIdTextBox").val();
             var somethingName = "Something 3";
             var somethingId = "432";
 
             var removeLabel = '<label class="removeSomething">remove</label>';
             var listItem = '<li data-personid="' + personId + '" data-somethingid="' + somethingId + '">' + removeLabel + somethingName + '</li>';
             $("ul").append(listItem);
         });
 
 
         $(".removeSomething").live('click'function () {
             var personIdSelector = $(this).parent().data("personId");
             var somethingIdSelector = $(this).parent().data("somethingId");
             alert("here" + personIdSelector + " " + somethingIdSelector);
             $(this).parent().css("text-decoration""line-through");
         });
     </script>

Monday, May 30, 2011

Scenario management for .ashx handlers.

    /// <summary>
    /// Scenario has three parts
    /// 1. A test that returns true or false
    /// 2. A method to run if the test is true.
    /// 3. A response object that has some details such as error messages.
    /// 
    /// Benefits, your main entry point to the application is clean.
    /// The scenarios should be of a relatively similar type, this is not a service locator.
    /// For example the file up loader has three different save types, so there are three different scenarios.
    /// 
    /// </summary>
    public class ScenarioHttpContext
    {
 
        public Func<HttpContextbool> Test { getset; }
        public Func<HttpContextScenarioResponse> DoWork { getset; }
 
        [DebuggerStepThrough]
        public ScenarioHttpContext(Func<HttpContextbool> test, Func<HttpContextScenarioResponse> doWork)
        {
            Test = test;
            DoWork = doWork;
        }
 
        [DebuggerStepThrough]
        public static List<ScenarioResponse> RunActions(List<ScenarioHttpContext> scenarios, HttpContext context,bool runAll = false)
        {
            Contract.Requires<ArgumentNullException>(context != null);
            Contract.Requires<ArgumentNullException>( scenarios != null);
            Contract.Requires<ArgumentOutOfRangeException>(scenarios != null || scenarios.Count > 0, "Cannot be null or have zero list items.");
            Trace.WriteLine("Starting ->" + MethodBase.GetCurrentMethod().Name); 
            Trace.Indent();
            var resp = new List<ScenarioResponse>();
           
            //if the test returns true then run the method
            foreach (var scenario in scenarios.Where(scenario => scenario.Test(context)))
            {
               
                Trace.WriteLine(scenario + "Was called.");
                var a = scenario.DoWork(context);
                a.Name = scenario.ToString();
 
                resp.Add(a);
                
                if (!runAll) { break; }
            }
 
            Trace.WriteLine(string.Format("A total of {0} scenarios evaluated true and ran.", resp.Count.ToString()));
            Trace.Unindent();
            Trace.WriteLine("Ending ->" + MethodBase.GetCurrentMethod().Name);
            Trace.Flush();
            return resp;
        }
    }
 
    public class ScenarioResponse
    {
        public string Name { getset; }
        public bool Success { getset; }
        public string ErrorMsg { getset; }
    }
 
 
    public static class ScenarioHttpContextExtensions
    {
       /// <summary>
       /// 
       /// </summary>
       /// <param name="scenario">Unit of work</param>
       /// <param name="test">If statement to determine if this scenario should be run.</param>
       /// <param name="workToDo">The work to do if the scenario test is true</param>
        [DebuggerStepThrough]
        public static void AddNew(this List<ScenarioHttpContext> scenario ,Func<HttpContextbool> test, Func<HttpContext,ScenarioResponse > workToDo)
        {
            Contract.Requires<ArgumentNullException>(scenario != null);
            scenario.Add(new ScenarioHttpContext(test, workToDo));
        }
    }

Saturday, May 21, 2011

jquery Autocomplete with previous dropdown

The html is simple we have a  dropdown box, ddlist and a textbox called textbox.
Please double check the names, I changed them in notepad.

This solution also fixes the issue where the dropdown list item is cashing the selected value from page load.

The first function erases the value of the textbox when the dropdown list changes.


$("#ddlist").change(function () {
    alert($('#ddlist option:selected').text());
    $("#textbox").val('');
});
 
This function kicks off the autocomplete process when the user clicks in the box.
If the value of the ddl is not good, then throw up a hint. 
$("#textbox").live("focus"function () {
    var marketVal = $('#ddlist option:selected').text();
    if (marketVal != '') {
        var sourceUrl = 'mypage.ashx?action=dosomething&ddlistName=' + $('#ddlist option:selected').text();
        $("#textbox").autocomplete({
            source: sourceUrl,
            minLength: 2
            //select: function (event, ui) { $("#SubMarket").val(ui.item.id); }
        });
    } else {
        alert("Please choose a Market item first");
    }
});

Tuesday, May 3, 2011

String.Format

Such a simple, but commonly over looked function.  When writing inline sql, (yes, it still happens), try to use string.format(...) vs. "text" + "text" + someVar.

I wish I had time to post samples of both, so you can see the readablity difference.

Wednesday, March 16, 2011

Simple.data

https://github.com/markrendle/Simple.Data/wiki/Finding-data

After listening to a podcast on Simple.Data I decided to check it out for a small project I was working on.
I like it and it works well for small sites that need an active record patten and more.

My first piece of advice is to use NuGet to add the libraries to your solution.  I don't think the download on the site gives you the latest version. Second,  understanding the dynamic type in C# 4.0 is helpful.

See Mark's wiki to see how simple.data works.

I had a design issue and here is how I worked around it.  I had properties in my class that were not defined in my database.  There may be an override to stop the errors.  My solution was to create a private class that was the same name as my table that only had the properties from the database.  Then I created a very simple mapping method. I could have used something dynamic, or named arguments, but I figured with a private class in my repository would give me flexibility to do things like datetime corrections and sure enough that happened.

Why go through all that?  Why not use NHibernate and be done. My application is going to be plugged into a CMS system and I do not know if the NHibernate session would play nicely with hosting package and I don't have time to find out.

https://github.com/markrendle/Simple.Data/wiki/Finding-data