• Using TestDriven Development and the RedGreenRefactor Workflow


    With test-driven development (TDD), you use unit tests to help design your code. This can be an odd
    concept if you are used to testing after you have finished coding, but there is a lot of sense in this
    approach. The key concept is a development workflo w called red-green-refactor. It works like this:
    1.   Determine that you need to add a new feature or method to your application.
    2.   Write the test that will validate the behavior of the new feature when it is
    written.
    3.   Run the test and get a red light.
    4.   Write the code that implements the new feature.
    5.   Run the test again and correct the code until you get a green light.
    6.   Refactor the code if required. For example, reorganize the statements, rename
    the variables, and so on. 
    7.   Run the test to confirm that your changes have not changed the behavior of
    your additions. 
     
    This workflow is repeated fo r every feature you add. 
    Let’s walk through an example so you can see how it works. Let’s imagine the behavior we want is
    the ability to add a bid to an item, but only if the bid  is higher than all previous bids for that item. First,
    we will add a stub method to the  Item class, as shown in Listing 4-8.
    Listing 4-8. Adding a Stub Method to the Item Class
    using System;
    using System.Collections.Generic;
     
    namespace TheMVCPattern.Models {
        public class Item {
            public int ItemID { get; private set; } // The unique key
            public string Title { get; set; }
            public string Description { get; set; }
            public DateTime AuctionEndDate { get; set; }
            public IList<Bid> Bids { get; private set; }
     
            public void AddBid(Member memberParam, decimal amountParam) {
                throw new NotImplementedException();
            }
        }
    }

    It’s obvious that the AddBid method, shown in bold, doesn’t display the required behavior, but we
    n’t let that stop us. The key to TDD is to test for the correct behavior before  implementing the feature.
    are going to test for three different aspects of the behavior we are seeking to implement: 

    •  When there are no bids, any bid value can be added. 
    •  When there are existing bids, a higher value bid can be added. 
    •  When there are existing bids, a lower value bid cannot be added.
     
    To do this, we create three test methods, which are shown in Listing 4-9.
    Listing 4-9. Three Test Fixtures
    [TestMethod()]
    public void CanAddBid() {
     
        // Arrange - set up the scenario
        Item target = new Item(); 
        Member memberParam = new Member();
        Decimal amountParam = 150M;
     
        // Act - perform the test
        target.AddBid(memberParam, amountParam);
                
        // Assert - check the behavior
        Assert.AreEqual(1, target.Bids.Count());
        Assert.AreEqual(amountParam, target.Bids[0].BidAmount);
    }
     

    [TestMethod()]
    [ExpectedException(typeof(InvalidOperationException))]
    public void CannotAddLowerBid() {
     
        // Arrange
        Item target = new Item();
        Member memberParam = new Member();
        Decimal amountParam = 150M;
     
        // Act
        target.AddBid(memberParam, amountParam);
        target.AddBid(memberParam, amountParam - 10);
    }
     
    [TestMethod()]
    public void CanAddHigherBid() {
     
        // Arrange
        Item target = new Item();
        Member firstMember = new Member();
        Member secondMember = new Member();
        Decimal amountParam = 150M;
     
        // Act
        target.AddBid(firstMember, amountParam);
        target.AddBid(secondMember, amountParam + 10);

      // Assert
        Assert.AreEqual(2, target.Bids.Count());
        Assert.AreEqual(amountParam + 10, target.Bids[1].BidAmount);
    }
     
    We’ve created a unit test for each of the behaviors we want to see. The test methods follow the
    arrange/act/assert pattern to create, test, and va lidate one aspect of the overall behavior. The
    CannotAddLowerBid method doesn’t have an assert part in the method body because a successful test is an
    exception being thrown, which we assert by applying the  ExpectedException attribute on the test method.

    As we would expect, all of these tests fail when we run them, as shown in Figure 4-10.

    image

    Figure 4-10.  Running the unit tests for the first time
    We can now implement our first pass at the AddBid method, as shown in Listing 4-10.
    Listing 4-10.  Implementing the AddBid Method
    using System;
    using System.Collections.Generic;
     
    namespace TheMVCPattern.Models {
        public class Item {

            public int ItemID { get; private set; } // The unique key
            public string Title { get; set; }
            public string Description { get; set; }
            public DateTime AuctionEndDate { get; set; }
            public IList<Bid> Bids { get; set; }
     
            public Item() {
                Bids = new List<Bid>();
            }
     
            public void AddBid(Member memberParam, decimal amountParam) {
                Bids.Add(new Bid() {
                    BidAmount = amountParam,
                    DatePlaced = DateTime.Now,
                    Member = memberParam
                });
            }
        }
    }
     
    We’ve added an initial implementation of the AddBid method to the  Item  class. We’ve also added a
    simple constructor so we can create instances of Item and ensure that the collection of Bid objects is
    properly initialized. Running the unit tests again generates better results, as shown in Figure 4-11.

    image

    Two of the three unit tests have passed. The one that has failed is CannotAddLowerBid. We didn’t add
    any checks to make sure that a bid is higher than previous bids on the item. We need to modify our
    mplementation to put this logic in place, as shown in Listing 4-11.

    Listing 4-11.  Improving the Implementation of the AddBid Method
    using System;
    using System.Collections.Generic;
    using System.Linq;
     
    namespace TheMVCPattern.Models {
        public class Item {
            public int ItemID { get; private set; } // The unique key
            public string Title { get; set; }
            public string Description { get; set; }
            public DateTime AuctionEndDate { get; set; }
            public IList<Bid> Bids { get; set; }
     
            public Item() {
                Bids = new List<Bid>();
            }
     
            public void AddBid(Member memberParam, decimal amountParam) {
     
                if (Bids.Count() == 0 || amountParam > Bids.Max(e => e.BidAmount)) {
                    Bids.Add(new Bid() {
                        BidAmount = amountParam,
                        DatePlaced = DateTime.Now,
                        Member = memberParam
                    });
                } else {
                    throw new InvalidOperationException("Bid amount too low");
                }
            }
        }
    }
     
    You can see that we have expressed the error condition in such a way as to satisfy the unit test we
    wrote before we started coding; that is, we throw an InvalidOperationException when a bid is received
    that is too low. 

    Each time we change the implementation of the  AddBid method, we run our unit tests again. The
    results are shown in Figure 4-12.

    image

    Success! We have implemented our new feature such that  it passes all of the unit tests. The last step
    is to take a moment and be sure that our tests really do test all aspects of the behavior or feature we are
    implementing. If so, we are finished. If not, then we add more tests and repeat the cycle, and we keep
    going until we are confident that we have a comprehensive set of tests and an implementation that
    passes them all.
    This cycle is the essence of TDD. There is a lot  to recommend it as a development style, not least
    because it makes a programmer think about how a change or enhancement should behave before  the
    coding starts. You always have a clear end point in view and a way to check that you are there. And if you
    have unit tests that cover the rest of your application, you can be sure that your additions have not
    changed the behavior elsewhere.

  • 相关阅读:
    1. jQuery中的DOM操作
    jQuery查找节点(选择器)
    机器学习基础
    CRF
    NP
    LP
    kernel
    SVM
    凸优化和对偶
    语音识别 -- 概述
  • 原文地址:https://www.cnblogs.com/gossip/p/2470110.html
Copyright © 2020-2023  润新知