2012-01-27 6 views
0

私はTDDを使ってメソッドを書き直そうとしています。レガシーコードをTDDコードに変換する手助けができますか?初心者が髪を引き出す

ここでは、データベースロジックを持たない独自の方法があり、それを書き直そうとしています。私はちょうど壁にぶつかり、それを仕上げる方法を理解していないので、それは完全ではありません。

私は勉強しようとしているし、それを働かせることができないので、いくつかの助けが必要です。読んでくれてありがとう。

//Original Method 

    public class StringCalculator() 
    { 

    public List<ShipmentInformation> GetBoxRange(int BoxSize, int Quantity, ref string DVDType, ref string ErrorMessage) 
    { 

     //Get Connection String 


     //Do Database Queries and return shipmentInfo variable as List<ShipmentInformation> 

     var DVDTotals = shipmentInfo.GroupBy(x => x.DVDType).Select(x => new { DVDType = x.Key, Total = x.Sum(y => (y.DVDEndID - y.DVDStartID) + 1) }); 

     if (DVDTotals.Count() == 0 || DVDTotals.All(x => x.Total < Quantity)) 
     { 
      ErrorMessage = "There is not enough data to create a shipment based on the quantity"; 
      return new List<ShipmentInformation>(); 
     } 


     //Select the one with the largest amount of stock 
     var LargestDVDType = DVDTotals.Aggregate((l, r) => l.Total > r.Total ? l : r).DVDType; 

     var LargestDVDTypeSelection = shipmentInfo.Where(x => x.DVDType == LargestDVDType); 

     long previousDVDStartID = 0; 

     //Make sure ranges are sequential 
     List<ShipmentInformation> SequentialBoxResults = new List<ShipmentInformation>(); 
     foreach (var item in LargestDVDTypeSelection) 
     { 
      if (item.DVDStartID - previousDVDStartID == BoxSize || previousDVDStartID == 0) 
      { 
       SequentialBoxResults.Add(item); 
      } 
      else 
      { 
       SequentialBoxResults.Clear(); 
       SequentialBoxResults.Add(item); 
      } 

      previousDVDStartID = item.DVDStartID; 

      if (BoxSize * SequentialBoxResults.Count == Quantity) 
      { 
       break; 
      } 
     } 

     if (SequentialBoxResults.Count == 0 || BoxSize * SequentialBoxResults.Count != Quantity) 
     { 
      ErrorMessage = "There are no available ranges to create a shipment based on the quantity"; 
      return new List<ShipmentInformation>(); ; 
     } 

     List<ShipmentInformation> Results = new List<ShipmentInformation>(); 
     var Genres = SequentialBoxResults.GroupBy(x => x.Genre); 
     foreach (var Genre in Genres) 
     { 
      var orderedGenres = Genre.OrderBy(x => x.DVDStartID); 

      ShipmentInformation shipment = new ShipmentInformation(); 
      shipment.Genre = Genre.Key; 
      shipment.DVDStartID = orderedGenres.First().DVDStartID; 
      var lastItem = orderedGenres.Last(); 
      shipment.DVDEndID = lastItem.DVDEndID; 
      shipment.DVDType = lastItem.DVDType; 

      Results.Add(shipment); 
     } 

     //We have our shipment recordsnow split them up if any are over 75000 

     for (int i = 0; i < Results.Count; i++) 
     { 
      long rangeSize = Results[i].DVDEndID - Results[i].DVDStartID + 1; 

      double noOfLoops = Math.Ceiling(rangeSize/75000D); 
      long remainder = rangeSize % 75000; 

      if (noOfLoops > 1) 
      { 
       bool AddedRecord = false; 
       for (int j = 0; j < noOfLoops; j++) 
       { 
        long shipmentSize = 0; 

        if (j == (noOfLoops - 1)) 
        { 
         shipmentSize = remainder; 
         if (AddedRecord) 
          Results.Add(new ShipmentInformation() { DVDStartID = Results.Last().DVDEndID + 1, DVDEndID = Results.Last().DVDEndID + 1 + (shipmentSize - 1), Genre = Results.Last().Genre }); 
         else 
          Results.Add(new ShipmentInformation() { DVDStartID = Results[i].DVDEndID + 1, DVDEndID = Results[i].DVDEndID + 1 + (shipmentSize - 1), Genre = Results[i].Genre }); 
        } 
        else 
        { 
         shipmentSize = 75000; 
         if (j == 0) 
         { 
          Results[i].DVDEndID = Results[i].DVDStartID + (shipmentSize - 1); 
         } 
         else if (j == 1) 
         { 
          Results.Add(new ShipmentInformation() { DVDStartID = Results[i].DVDEndID + 1, DVDEndID = Results[i].DVDEndID + 1 + (shipmentSize - 1), Genre = Results[i].Genre }); 
          AddedRecord = true; 
         } 
         else 
         { 
          Results.Add(new ShipmentInformation() { DVDStartID = Results.Last().DVDEndID + 1, DVDEndID = Results.Last().DVDEndID + 1 + (shipmentSize - 1), Genre = Results.Last().Genre }); 
          AddedRecord = true; 
         } 
        } 
       } 
      } 
     } 

     return Results; 

    } 
    } 

    //New Method with Tests 

    public List<ShipmentInformation> GetBoxRange(int BoxSize, int Quantity, DateTime CutOffDate, IDataProvider Provider, ref string DVDType, ref string ErrorMessage) 
    { 
     if (BoxSize == 0) 
     { 
      ErrorMessage = "Please enter a BoxSize"; 
     } 

     if (Quantity == 0) 
     { 
      ErrorMessage = "Please enter a Quantity"; 
     } 


     if (!String.IsNullOrWhiteSpace(ErrorMessage)) 
     { 
      return new List<ShipmentInformation>(); 
     } 

     List<ShipmentInformation> Data = Provider.GetData(); 

     if (Data.Count == 0) 
     { 
      ErrorMessage = "Database failed to return data"; 
      return new List<ShipmentInformation>(); 
     } 

     List<ShipmentInformation> OrderedData = GetSequentialBoxes(Data, BoxSize, Quantity); 

     if (OrderedData.Count == 0) 
     { 
      ErrorMessage = "No sequential data found"; 
      return new List<ShipmentInformation>(); 
     } 

     //I'm not sure how to continue from here - I started writing GetRecordsPerGenre but got lost in what I'm trying to do. I still need to check if size is over 75000 

     return OrderedData; 
    } 

    public virtual List<ShipmentInformation> GetSequentialBoxes(List<ShipmentInformation> Data, int BoxSize, int Quantity) 
    { 
     if (Data.Count == 0) 
      return new List<ShipmentInformation>(); 

     var orderedData = Data.OrderBy(x => x.DVDStartID); 
     if (!orderedData.SequenceEqual(Data)) 
      return new List<ShipmentInformation>(); 

     var DVDTotals = Data.GroupBy(x => x.DVDType).Select(x => new { DVDType = x.Key, Total = x.Sum(y => (y.DVDEndID - y.DVDStartID) + 1) }); 

     if (DVDTotals.Count() == 0 || DVDTotals.All(x => x.Total < Quantity)) 
     { 
      return new List<ShipmentInformation>(); 
     } 

     var LargestDVDType = DVDTotals.Aggregate((l, r) => l.Total > r.Total ? l : r).DVDType; 

     Data = Data.Where(x => x.DVDType == LargestDVDType).ToList(); 

     List<ShipmentInformation> returnData = new List<ShipmentInformation>(); 
     long previousDVDStartID = 0; 
     foreach (var item in Data) 
     { 
      if (previousDVDStartID == 0 || item.DVDStartID - previousDVDStartID == BoxSize) 
      { 
       returnData.Add(item); 
      } 
      else 
      { 
       returnData.Clear(); 
       returnData.Add(item); 
      } 

      previousDVDStartID = item.DVDStartID; 

      if (returnData.Count * BoxSize == Quantity) 
       break; 
     } 

     return returnData.OrderBy(x => x.DVDStartID).ToList(); 
    } 

    public List<ShipmentInformation> GetRecordsPerGenre(List<ShipmentInformation> Data) 
    { 
     List<ShipmentInformation> Results = new List<ShipmentInformation>(); 
     var Genres = Data.GroupBy(x => x.Genre); 
     foreach (var Genre in Genres) 
     { 
      var orderedGenres = Genre.OrderBy(x => x.DVDStartID); 

      ShipmentInformation shipment = new ShipmentInformation(); 
      shipment.Genre = Genre.Key; 
      shipment.DVDStartID = orderedGenres.First().DVDStartID; 
      var lastItem = orderedGenres.Last(); 
      shipment.DVDEndID = lastItem.DVDEndID; 
      shipment.DVDType = lastItem.DVDType; 

      Results.Add(shipment); 
     } 

     return Results; 
    } 




    //Tests 

    [TestFixture] 
    public class GetBoxRangeMethod 
    { 
     private StringCalculator CreateNewCalculator() 
     { 
      return new StringCalculator(); 
     } 

     [TestCase(0, 1)] 
     [TestCase(1, 0)] 
     public void ZeroValuesForBoxSizeOrQuantity_ReturnsErrorAndEmptyList(int BoxSize, int Quantity) 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      string ErrorMessage = ""; 
      string ChipType = ""; 
      FakeDataProvier provider = new FakeDataProvier(new List<ShipmentInformation>()); 
      List<ShipmentInformation> result = sc.GetBoxRange(BoxSize, Quantity, new DateTime(2012, 01, 01), "A", provider, ref ChipType, ref ErrorMessage); 

      Assert.AreNotEqual("", ErrorMessage); 
      Assert.AreEqual(0, result.Count); 
     } 

     [Test] 
     public void EmptyBookTypeString_ReturnsErrorAndEmptyList() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      string ErrorMessage = ""; 
      string ChipType = ""; 

      FakeDataProvier provider = new FakeDataProvier(new List<ShipmentInformation>()); 

      List<ShipmentInformation> result = sc.GetBoxRange(1, 1, new DateTime(2012, 01, 01), "", provider, ref ChipType, ref ErrorMessage); 

      Assert.AreNotEqual("", ErrorMessage); 
      Assert.AreEqual(0, result.Count); 
     } 

     [Test] 
     public void EmptyDBData_ReturnsErrorAndEmptyList() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      string ErrorMessage = ""; 
      string ChipType = ""; 
      FakeDataProvier provider = new FakeDataProvier(new List<ShipmentInformation>()); 

      List<ShipmentInformation> result = sc.GetBoxRange(1, 1, new DateTime(2012, 01, 01), "A", provider, ref ChipType, ref ErrorMessage); 

      Assert.AreNotEqual("", ErrorMessage); 
      Assert.AreEqual(0, result.Count); 
     } 

     [Test] 
     public void EmptyOrderedData_ReturnsErrorAndEmptyList() 
     { 
      FakeShipmentCalculator sc = new FakeShipmentCalculator(); 

      string ErrorMessage = ""; 
      string ChipType = ""; 
      FakeDataProvier provider = new FakeDataProvier(new List<ShipmentInformation>() { new ShipmentInformation() { ChipType = "A", StartPP = 1, EndPP = 2, JacketNo = "A", ReqNo = "B" } }); 

      List<ShipmentInformation> result = sc.GetBoxRange(1, 1, new DateTime(2012, 01, 01), "A", provider, ref ChipType, ref ErrorMessage); 

      Assert.AreNotEqual("", ErrorMessage); 
      Assert.AreEqual(0, result.Count); 
     } 

    } 

    //Integration test 
    [TestFixture] 
    public class GetDataMethod 
    { 

    } 

    [TestFixture] 
    public class GetSequentialBoxes 
    { 
     private StringCalculator CreateNewCalculator() 
     { 
      return new StringCalculator(); 
     } 

     [Test] 
     public void MethodCalled_DoesntReturnNull() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> result = sc.GetSequentialBoxes(new List<ShipmentInformation>(), 100, 1); 

      Assert.IsNotNull(result); 
     } 

     [Test] 
     public void EmptyDataPassedIn_ReturnsEmptyData() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> result = sc.GetSequentialBoxes(new List<ShipmentInformation>(), 100, 1); 

      Assert.AreEqual(0, result.Count); 
     } 

     [Test] 
     public void OrderedData_ReturnsOrderedData() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> inputData = new List<ShipmentInformation>(); 

      ShipmentInformation data = new ShipmentInformation() { ChipType = "A", StartPP = 1, EndPP = 2, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "A", StartPP = 3, EndPP = 4, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      List<ShipmentInformation> result = sc.GetSequentialBoxes(inputData, 2, 1); 

      ShipmentInformation firstItem = result.FirstOrDefault(); 
      ShipmentInformation secondItem = result.LastOrDefault(); 

      Assert.IsTrue(firstItem.StartPP == 1 && secondItem.StartPP == 3); 
     } 

     [Test] 
     public void UnOrderedData_ReturnsEmptyData() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> inputData = new List<ShipmentInformation>(); 

      ShipmentInformation data = new ShipmentInformation() { ChipType = "A", StartPP = 3, EndPP = 4, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "A", StartPP = 1, EndPP = 2, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      int NUMBER_GREATER_THAN_ONE = 2; 
      List<ShipmentInformation> result = sc.GetSequentialBoxes(inputData, NUMBER_GREATER_THAN_ONE, 1); 

      Assert.AreEqual(0, result.Count); 
     } 

     [Test] 
     public void SequenceJumps_ClearsListAndStartsAgain() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> inputData = new List<ShipmentInformation>(); 

      ShipmentInformation data = new ShipmentInformation() { ChipType = "A", StartPP = 1, EndPP = 2, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "A", StartPP = 5, EndPP = 6, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      List<ShipmentInformation> result = sc.GetSequentialBoxes(inputData, 2, 1); 

      Assert.IsTrue(result.First().StartPP == 5); 
     } 

     [Test] 
     public void LargestNumberOfItemsWithSameChipType_ReturnsDataWithOnlyThatChipType() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> inputData = new List<ShipmentInformation>(); 

      ShipmentInformation data = new ShipmentInformation() { ChipType = "A", StartPP = 1, EndPP = 2, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "A", StartPP = 3, EndPP = 4, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "B", StartPP = 5, EndPP = 6, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      int BoxSizeSlashSequenceJumpAllowed = 2; 

      List<ShipmentInformation> result = sc.GetSequentialBoxes(inputData, BoxSizeSlashSequenceJumpAllowed, 1); 

      Assert.IsTrue(result.All(x => x.ChipType == "A")); 
     } 

     [Test] 
     public void TotalNumberOfRecordsPerChipTypeLessThanQuantity_ReturnsEmptyData() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> inputData = new List<ShipmentInformation>(); 

      ShipmentInformation data = new ShipmentInformation() { ChipType = "A", StartPP = 1, EndPP = 2, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "A", StartPP = 3, EndPP = 4, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "B", StartPP = 5, EndPP = 6, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      int BoxSizeSlashSequenceJumpAllowed = 2; 
      int Quantity = 5; 

      List<ShipmentInformation> result = sc.GetSequentialBoxes(inputData, BoxSizeSlashSequenceJumpAllowed, Quantity); 

      Assert.AreEqual(0, result.Count); 
     } 

     [Test] 
     public void DataReturned_WhenQuantityReached() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> inputData = new List<ShipmentInformation>(); 

      ShipmentInformation data = new ShipmentInformation() { ChipType = "A", StartPP = 1, EndPP = 2, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "A", StartPP = 3, EndPP = 4, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      data = new ShipmentInformation() { ChipType = "A", StartPP = 5, EndPP = 6, JacketNo = "A", ReqNo = "B" }; 
      inputData.Add(data); 

      int BoxSizeSlashSequenceJumpAllowed = 2; 
      int Quantity = 4; 

      List<ShipmentInformation> result = sc.GetSequentialBoxes(inputData, BoxSizeSlashSequenceJumpAllowed, Quantity); 

      Assert.AreEqual(2, result.Count); 
     } 
    } 

    [TestFixture] 
    public class GetRecordsPerGenre 
    { 
     private StringCalculator CreateNewCalculator() 
     { 
      return new StringCalculator(); 
     } 

     [Test] 
     public void MethodCalled_DoesntReturnNull() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> result = sc.GetRecordsPerSerialRange(new List<ShipmentInformation>()); 

      Assert.IsNotNull(result); 
     } 

     [Test] 
     public void EmptyDataPassedIn_ReturnsEmptyData() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> result = sc.GetRecordsPerSerialRange(new List<ShipmentInformation>()); 

      Assert.AreEqual(0, result.Count); 
     } 

     [Test] 
     public void Data_ReturnsGroupedByData() 
     { 
      StringCalculator sc = CreateNewCalculator(); 

      List<ShipmentInformation> inputData = new List<ShipmentInformation>(); 

      ShipmentInformation data = new ShipmentInformation(); 
      data.ChipType = "A"; 
      data.ReqNo = "B"; 
      data.JacketNo="C"; 
      data.StartPP = 1; 
      data.EndPP = 2; 

      inputData.Add(data); 

      data = new ShipmentInformation(); 

      data.ChipType = "A"; 
      data.ReqNo = "B"; 
      data.JacketNo = "C"; 
      data.StartPP = 1; 
      data.EndPP = 2; 

      inputData.Add(data); 

      List<ShipmentInformation> result = sc.GetRecordsPerSerialRange(inputData); 

      Assert.AreEqual(1, result.Count); 
     } 
    } 
+0

"何をするのが最善で、私は物事を模倣する必要がありますか?"これは何を意味するのでしょうか?あなたにはテストがあります。彼らは失敗するのだろうか?あなたはコードを書く必要があります。彼らはパスしますか?あなたはコードを書いています。あなたはどこにいるのですか?また、コードサンプルを、問題を示す**最小の**コードサンプルに減らしてください。 **特に**あなたの問題は何ですか? –

+0

は、多くのコードを分割して征服しています。クラスを1つずつ再構築し、メソッドをスタブしたり、途中でテストしたり、ビルド時にテストクラスやメソッドを構築したりしてください。あなたがこれをリファクタリングするのに気をつけているなら、テストクラスとメソッドを構築する時間を正当化することが重要です。 – jamesTheProgrammer

+0

あなたのメソッドは、新しいものであっても、あまりにも多くのことをしようとしています。メソッド名が示すように、目的はボックス範囲を取得することです。ただし、エラーメッセージの処理も行います。これが唯一のことではありません。これにより、テストするのがずっと難しくなります。 – Holystream

答えて

2

ジョンでは、あなたはノブのためにあまりにも多くを噛んでいるかもしれません。既存のものではなく新しい機能でTDDを実装してください。このシナリオでは、テスト、TDD、モックを導入するだけでなく、リファクタリング(まだ別の新しいコンセプト)を導入しました。あなたはグリーンフィールドコードでTDDの基本を持っていたら

、あなたはその後、リファクタリングと一緒にブラウンフィールドコードを適用することができます。

最後のノート:TDDはモックを必要としないが、モックはTDDとよく果たしている独立した概念であるが、これは必須ではありません。 TDD、単純に言えば、テストを通して設計を推進しているということです。

+0

ありがとうございます、あなたが正しいかもしれません。私の混乱の一部は嘲笑とは何か、どうすればそれが必要なのかを知ることができます:) – Jon

+0

Mockingでは、テストで使用する "擬似"オブジェクトを作成できます。おそらくそれらを使用する必要があります。この場合、インタフェースに基づいて模擬データプロバイダを作成します。 moqというmockingライブラリを見てください(多くのうちの1つだけですが、私が使っているものです) – Magrangs

2

ユニットテストを効果的に行うには、いくつかの設計原則を遵守する必要があります。緩いカップリング、懸念の分離と依存性注入。

//Get Connection String 
//Do Database Queries and return shipmentInfo variable as List<ShipmentInformation> 
:この理由は、私はあなたが持っていたコードの上、あなたの最初の方法に気づいた(あなたが行う必要があります何である)、あなたのテストでモックを使用することはできません、なし、

です

私はここから、実際にここで必要なものすべてをインスタンス化してDBにクエリすると仮定します。これはベストプラクティスではなく、おそらく問題の根源です。あなたは抽象的な抽象ではなく、抽象的でなければなりません。 'リポジトリ'インタフェース(またはそれに類するもの)のインスタンスは、コンストラクタインジェクションを使用して渡す必要があります。このことができますhttp://www.amazon.co.uk/Professional-ASP-NET-Design-Patterns-Millett/dp/0470292784

希望:

あなたが始めるのに良い本はこれだろう。

+0

新しいメソッドでIDataProviderを使用したので、これを選択しました。あなたの答えをありがとう、ありがとう – Jon

+0

問題ありません。私は徹底的に上記の本をお勧めします、それは確かに読む価値があります。 – Magrangs

関連する問題