2015-01-03 4 views
7

特定の順序で特定のイベントシーケンスが発生したことを主張する私のユニットテストのヘルパーメソッドがあります。コードは以下の通りである:次のように予期したイベントのテストヘルパーシーケンスの重複イベントの報告

public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction) 
{ 
    var expectedSequence = new Queue<int>(); 
    for (int i = 0; i < subscribeActions.Count; i++) 
    { 
     expectedSequence.Enqueue(i); 
    } 

    ExpectEventSequence(subscribeActions, triggerAction, expectedSequence); 
} 

    public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction, Queue<int> expectedSequence) 
    { 
     var fired = new Queue<int>(); 
     var actionsCount = subscribeActions.Count; 

     for(var i =0; i< actionsCount;i++) 
     { 
      subscription((o, e) => 
       { 
        fired.Enqueue(i); 
       }); 
     } 

     triggerAction(); 

     var executionIndex = 0; 

     var inOrder = true; 

     foreach (var firedIndex in fired) 
     { 

      if (firedIndex != expectedSequence.Dequeue()) 
      { 
       inOrder = false; 
       break; 
      } 

      executionIndex++; 
     } 

     if (subscribeActions.Count != fired.Count) 
     { 
      Assert.Fail("Not all events were fired."); 
     } 

     if (!inOrder) 
     { 
      Assert.Fail(string.Format(
       CultureInfo.CurrentCulture, 
       "Events were not fired in the expected sequence from element {0}", 
       executionIndex)); 
     } 

    } 

使用例は次のとおりです。

[Test()] 
    public void FillFuel_Test([Values(1, 5, 10, 100)]float maxFuel) 
    { 
     var fuelTank = new FuelTank() 
     { 
      MaxFuel = maxFuel 
     }; 

     var eventHandlerSequence = new Queue<Action<EventHandler>>(); 

     eventHandlerSequence.Enqueue(x => fuelTank.FuelFull += x); 

     //Dealing with a subclass of EventHandler 
     eventHandlerSequence.Enqueue(x => fuelTank.FuelChanged += (o, e) => x(o, e)); 

     Test.ExpectEventSequence(eventHandlerSequence,() => fuelTank.FillFuel()); 
    } 

とテスト対象コード:

public float Fuel 
    { 
     get 
     { 
      return fuel; 
     } 
     private set 
     { 
      var adjustedFuel = Math.Max(0, Math.Min(value, MaxFuel)); 

      if (fuel != adjustedFuel) 
      { 
       var oldFuel = fuel; 

       fuel = adjustedFuel; 

       RaiseCheckFuelChangedEvents(oldFuel); 
      } 
     } 
    } 

    public void FillFuel() 
    { 
     Fuel = MaxFuel; 
    } 

    private void RaiseCheckFuelChangedEvents(float oldFuel) 
    { 
     FuelChanged.FireEvent(this, new FuelEventArgs(oldFuel, Fuel)); 

     if (fuel == 0) 
     { 
      FuelEmpty.FireEvent(this, EventArgs.Empty); 
     } 
     else if (fuel == MaxFuel) 
     { 
      FuelFull.FireEvent(this, EventArgs.Empty); 
     } 

     if (oldFuel == 0 && Fuel != 0) 
     { 
      FuelNoLongerEmpty.FireEvent(this, EventArgs.Empty); 
     } 
     else if (oldFuel == MaxFuel && Fuel != MaxFuel) 
     { 
      FuelNoLongerFull.FireEvent(this, EventArgs.Empty); 
     } 
    } 

だから、テストはFuelFilledFuelChanged前に解雇されることを想定していたが実際にはFuelChangedが最初に起動され、テストに失敗します。

しかし私のテストではなくFuelChangedは二回発射されていることを報告しているが、私はコードをステップ実行するとき、FuelChangedFuelChangedは1回のみ起動された後FuelFilledが発射されることは明らかです。

私はラムダは多分ループイテレータ変数がしかの最終値に設定するので、私はこれでループのために置き換えられたため、地元の状態で作業道とは何かだったと仮定:

 var subscriptions = subscribeActions.ToList(); 

     foreach (var subscription in subscriptions) 
     { 
      subscription((o, e) => 
       { 
        var index = subscriptions.IndexOf(subscription); 
        fired.Enqueue(index); 
       }); 
     } 

結果は同じですが、{1; 0}の代わりに{1; 1}が含まれています。

今私は、異なるサブスクリプション/インデックス状態を使用する代わりに、両方のイベントに同じラムダが割り当てられているのだろうかと思います。何か案は?

更新

は、私は私の実際のコードへの類似性にもかかわらず、(私の最初の結果と同じ)これまでに掲載の答えのいずれかで成功を得ることができなかったので、私は問題が私の FuelTankコード内の他の場所に位置して推定します。私は以下の FuelTankのための完全なコードを貼り付けました:

public class FuelTank 
{ 
    public FuelTank() 
    { 

    } 

    public FuelTank(float initialFuel, float maxFuel) 
    { 
     MaxFuel = maxFuel; 
     Fuel = initialFuel; 
    } 

    public float Fuel 
    { 
     get 
     { 
      return fuel; 
     } 
     private set 
     { 
      var adjustedFuel = Math.Max(0, Math.Min(value, MaxFuel)); 

      if (fuel != adjustedFuel) 
      { 
       var oldFuel = fuel; 

       fuel = adjustedFuel; 

       RaiseCheckFuelChangedEvents(oldFuel); 
      } 
     } 
    } 

    private float maxFuel; 

    public float MaxFuel 
    { 
     get 
     { 
      return maxFuel; 
     } 
     set 
     { 
      if (value < 0) 
      { 
       throw new ArgumentOutOfRangeException("MaxFuel", value, "Argument must be not be less than 0."); 
      } 
      maxFuel = value; 
     } 
    } 

    private float fuel; 

    public event EventHandler<FuelEventArgs> FuelChanged; 

    public event EventHandler FuelEmpty; 

    public event EventHandler FuelFull; 

    public event EventHandler FuelNoLongerEmpty; 

    public event EventHandler FuelNoLongerFull; 

    public void AddFuel(float fuel) 
    { 
     Fuel += fuel; 
    } 

    public void ClearFuel() 
    { 
     Fuel = 0; 
    } 

    public void DrainFuel(float fuel) 
    { 
     Fuel -= fuel; 
    } 

    public void FillFuel() 
    { 
     Fuel = MaxFuel; 
    } 

    private void RaiseCheckFuelChangedEvents(float oldFuel) 
    { 
     FuelChanged.FireEvent(this, new FuelEventArgs(oldFuel, Fuel)); 

     if (fuel == 0) 
     { 
      FuelEmpty.FireEvent(this, EventArgs.Empty); 
     } 
     else if (fuel == MaxFuel) 
     { 
      FuelFull.FireEvent(this, EventArgs.Empty); 
     } 

     if (oldFuel == 0 && Fuel != 0) 
     { 
      FuelNoLongerEmpty.FireEvent(this, EventArgs.Empty); 
     } 
     else if (oldFuel == MaxFuel && Fuel != MaxFuel) 
     { 
      FuelNoLongerFull.FireEvent(this, EventArgs.Empty); 
     } 
    } 
} 

FuelEventArgsは次のようになります。

public static class EventHandlerExtensions 
{ 
    /// <summary> 
    /// Fires the event. This method is thread safe. 
    /// </summary> 
    /// <param name="handler"> The handler. </param> 
    /// <param name="sender"> Source of the event. </param> 
    /// <param name="args"> The <see cref="EventArgs"/> instance containing the event data. </param> 
    public static void FireEvent(this EventHandler handler, object sender, EventArgs args) 
    { 
     var handlerCopy = handler; 

     if (handlerCopy != null) 
     { 
      handlerCopy(sender, args); 
     } 
    } 

    /// <summary> 
    /// Fires the event. This method is thread safe. 
    /// </summary> 
    /// <typeparam name="T"> The type of event args this handler has. </typeparam> 
    /// <param name="handler"> The handler. </param> 
    /// <param name="sender"> Source of the event. </param> 
    /// <param name="args"> The <see cref="EventArgs"/> instance containing the event data. </param> 
    public static void FireEvent<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs 
    { 
     var handlerCopy = handler; 

     if (handlerCopy != null) 
     { 
      handlerCopy(sender, args); 
     } 
    } 
} 

完全なテストコード:

public class FuelEventArgs : EventArgs 
{ 
    public float NewFuel 
    { 
     get; 
     private set; 
    } 

    public float OldFuel 
    { 
     get; 
     private set; 
    } 

    public FuelEventArgs(float oldFuel, float newFuel) 
    { 
     this.OldFuel = oldFuel; 
     this.NewFuel = newFuel; 
    } 
} 

FireEvent拡張メソッドがあるが、このようになりますテストの実行中に呼び出される他のコードはありません。私はUnity3Dエンジンのユニティテストツールのプラグインを介して、NUnitのテストフレームワークを使用しています

、.NETバージョン3.5(ISHは、それは私は信じて、モノラル2.0に近いです)、およびVisual Studio 2013

アップデート2 : - >ビジュアル期待通りにすべてのテストを実行し、自分のプロジェクト(Unity3Dの生態系の外側)に、コードやテストを抽出するので、私はユニティのバグまで、この1チョークする必要がありますするつもりだ後

スタジオブリッジ。

+0

興味深い質問...私は(私はあなたが実際にかかわらず、使用しているunittestのツールキットわからないよ)NUnitのを使って、自分の状況を再現してみましたが、私は唯一のFuelChangedイベント(インデックスの1つのトリガーを得ましたサブスクリプションは1に等しい)、続いてFuelFullイベント(サブスクリプションのインデックスは0に等しい)、そしてテストに失敗したFuelNoLongerEmptyイベントが続きます。 私はイベントハンドラーコードで何か違うものを持っている必要があります。 AFAIK、ラムダ式は定義上遅延評価されるため、実際に呼び出されるまで評価されず、デリゲート構文を使用するのと同じものにコンパイルされます。 – RvdV79

+0

それは本当にNUnitです、私はあなたが私に違う結果を持っているのは混乱しています。私は自分のコードを見て、それを質問にコピーする際に間違いがないかどうかを見ていきます。 –

+0

まず、サブスクリプションが不明であったため、パブリックstatic void ExpectEventSequenceの例の中で元のコードを変更する必要がありました。私はあなたの最後のforループを使用しました。 それ以外にも、イベントハンドラ(またはそれを使用するときのベース)が何であるかを知ることは良いことです。私はNUnit 2.6.4を使用しています。可能であれば、あなたの例に少し多くのコードを追加するかもしれません(多くの機密情報を明らかにせずに) – RvdV79

答えて

4

私はニックの質問に基づいて、以下の実装を持っています。

まず燃料タンクのためのクラス:

public class FuelTank 
{ 
    private float fuel; 

    //Basic classes for the event handling, could be done by providing a few simple delegates, 
    //but this is just to stick as close to the original question as possible. 
    public FuelChanged FuelChanged = new FuelChanged(); 
    public FuelEmpty FuelEmpty = new FuelEmpty(); 
    public FuelFull FuelFull = new FuelFull(); 
    public FuelNoLongerEmpty FuelNoLongerEmpty = new FuelNoLongerEmpty(); 
    public FuelNoLongerFull FuelNoLongerFull = new FuelNoLongerFull(); 


    public float MaxFuel { get; set; } 

    public float Fuel 
    { 
     get 
     { 
      return fuel; 
     } 
     private set 
     { 
      var adjustedFuel = Math.Max(0, Math.Min(value, MaxFuel)); 

      if (fuel != adjustedFuel) 
      { 
       var oldFuel = fuel; 

       fuel = adjustedFuel; 

       RaiseCheckFuelChangedEvents(oldFuel); 
      } 
     } 
    } 

    public void FillFuel() 
    { 
     Fuel = MaxFuel; 
    } 

    private void RaiseCheckFuelChangedEvents(float oldFuel) 
    { 
     FuelChanged.FireEvent(this, new FuelEventArgs(oldFuel, Fuel)); 

     if (fuel == 0) 
     { 
      FuelEmpty.FireEvent(this, EventArgs.Empty); 
     } 
     else if (fuel == MaxFuel) 
     { 
      FuelFull.FireEvent(this, EventArgs.Empty); 
     } 

     if (oldFuel == 0 && Fuel != 0) 
     { 
      FuelNoLongerEmpty.FireEvent(this, EventArgs.Empty); 
     } 
     else if (oldFuel == MaxFuel && Fuel != MaxFuel) 
     { 
      FuelNoLongerFull.FireEvent(this, EventArgs.Empty); 
     } 
    }  
} 

イベントハンドラのコードが行方不明になったように、私はこれを使用することを前提に作られました。前のコードブロックで説明されているように、簡単な代理人で簡単に実行できます。それは、そのため私は、この実装はまだありません最善であると思いますが、デバッグのために十分に適した、好みの問題だ:

public class FuelEventArgs : EventArgs 
{ 
    private float oldFuel, newFuel; 

    public FuelEventArgs(float oldFuel, float newFuel) 
    { 
     this.oldFuel = oldFuel; 
     this.newFuel = newFuel; 
    } 
} 

public class FuelEvents 
{  
    public event EventHandler FireEventHandler; 

    public virtual void FireEvent(object sender, EventArgs fuelArgs) 
    { 
     EventHandler handler = FireEventHandler; 
     if (null != handler) 
      handler(this, fuelArgs); 
    } 

} 

public class FuelChanged : FuelEvents 
{    

    public override void FireEvent(object sender, EventArgs fuelArgs) 
    { 
     Console.WriteLine("Fired FuelChanged"); 
     base.FireEvent(sender, fuelArgs); 
    } 
} 

public class FuelEmpty : FuelEvents 
{ 
    public override void FireEvent(object sender, EventArgs fuelArgs) 
    { 
     Console.WriteLine("Fired FuelEmpty"); 
     base.FireEvent(sender, fuelArgs); 
    } 
} 

public class FuelFull : FuelEvents 
{ 
    public override void FireEvent(object sender, EventArgs fuelArgs) 
    { 
     Console.WriteLine("Fired FuelFull"); 
     base.FireEvent(sender, fuelArgs); 
    } 
} 

public class FuelNoLongerEmpty : FuelEvents 
{ 
    public override void FireEvent(object sender, EventArgs fuelArgs) 
    { 
     Console.WriteLine("Fired FuelNoLongerEmpty"); 
     base.FireEvent(sender, fuelArgs); 
    } 
} 

public class FuelNoLongerFull : FuelEvents 
{ 
    public override void FireEvent(object sender, EventArgs fuelArgs) 
    { 
     Console.WriteLine("Fired FuelNoLongerFull"); 
     base.FireEvent(sender, fuelArgs); 
    } 
} 

そして、すべてのそれをテストするために、私は元からほとんどのコードを含む、このクラスを使用しました質問:

[TestFixture] 
public class Tests 
{ 
    public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction) 
    { 
     var expectedSequence = new Queue<int>(); 
     for (int i = 0; i < subscribeActions.Count; i++) 
     { 
      expectedSequence.Enqueue(i); 
     } 

     ExpectEventSequence(subscribeActions, triggerAction, expectedSequence); 
    } 

    public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction, Queue<int> expectedSequence) 
    { 
     var fired = new Queue<int>(); 
     var actionsCount = subscribeActions.Count; 

     //This code has been commented out due to the fact that subscription is unknown here. 
     //I stuck to use the last solution that Nick provided himself 

     //for (var i = 0; i < actionsCount; i++) 
     //{ 
     // subscription((o, e) => 
     // { 
     //  fired.Enqueue(i); 
     // }); 
     //} 

     var subscriptions = subscribeActions.ToList(); 

     foreach (var subscription in subscriptions) 
     { 
      subscription((o, e) => 
      { 
       var index = subscriptions.IndexOf(subscription); 
       Console.WriteLine("[ExpectEventSequence] Found index: {0}", index); 
       fired.Enqueue(index); 
      }); 
     } 

     triggerAction(); 

     var executionIndex = 0; 

     var inOrder = true; 

     foreach (var firedIndex in fired) 
     { 

      if (firedIndex != expectedSequence.Dequeue()) 
      { 
       inOrder = false; 
       break; 
      } 

      executionIndex++; 
      Console.WriteLine("Execution index: {0}", executionIndex); 
     } 

     if (subscribeActions.Count != fired.Count) 
     { 
      Assert.Fail("Not all events were fired."); 
     } 

     if (!inOrder) 
     { 
      Console.WriteLine("Contents of Fired Queue: {0}", PrintValues(fired)); 

      Assert.Fail(string.Format(
       CultureInfo.CurrentCulture, 
       "Events were not fired in the expected sequence from element {0}", 
       executionIndex)); 

     } 
    } 

    private static string PrintValues(Queue<int> myCollection) 
    { 
     return string.Format("{{0}}", string.Join(",", myCollection.ToArray())); 

    } 


    [Test()] 
    [ExpectedException(typeof(DivideByZeroException))] 
    public void FillFuel_Test([Values(1, 5, 10, 100)]float maxFuel) 
    { 

     var fuelTank = new FuelTank() 
     { 
      MaxFuel = maxFuel 
     }; 

     var eventHandlerSequence = new Queue<Action<EventHandler>>(); 

     eventHandlerSequence.Enqueue(x => fuelTank.FuelFull.FireEventHandler += x); 

     //Dealing with a subclass of EventHandler 
     eventHandlerSequence.Enqueue(x => fuelTank.FuelChanged.FireEventHandler += (o, e) => x(o, e)); 

     ExpectEventSequence(eventHandlerSequence,() => fuelTank.FillFuel()); 
    } 
} 

は今、NUnitのでテストを実行しているとき、私は次のような結果に気づいた:

トリガーしまった最初のイベントは、イベントをFuelChangedだった、これはメソッド内で発射キューを引き起こし

public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction, Queue<int> expectedSequence) 

{1}を含む。

トリガ次のイベントが発生キューが現在含まれていることを意味するFuelFullイベントがある: {1,0}ニックの質問に応じて予想通り。

トリガーする最後のイベントは、FuelNoLongerEmptyイベントです。このイベントは、テストに失敗します。

注:このコードとして
はまだ私は上記のコードは、ちょうど正しいことを行うようにラムダのは、いくつかの干渉を引き起こす可能性があるという事実の元の質問への答えを提供していません。

次のルールは、ラムダ式に変数のスコープに適用されます。それを参照 デリゲートがスコープの外に出るまで捕獲され

  • 変数は、ガベージコレクトされません。
  • ラムダ式に導入された変数は、
    外側のメソッドでは表示されません。
  • ラムダ式では、囲む方法からrefまたはoutパラメータを直接取り込むことはできません。
  • ラムダ式のreturn文では、
    囲みメソッドが返されません。
  • ラムダ式には、goto文、break文、 またはcontinue文が含まれていることがあります。ターゲットが本文外にあるか、本体に含まれています。

Nickの元の質問の問題は、キューを列挙していることが原因です。これらを列挙してラムダ式に直接渡している間は、参照を使用して作業します。トリックは、反復ループのスコープ内でローカル変数にコピーすることによって、実際にそれを参照解除することです。これはちょうどsmiechが彼のポストを参照しているものです。

EDIT:

私はあなたのためだけに、再びそれに見てきました。あなたが持っている '挑戦'は、焼成された辞書のインデックスとexpectedSequence.Dequeueを逆順で比較しているという事実だけではありませんか?キューはFIFOベースなので、デキュー時に最初に挿入されたものを取り出します。

私のコードによれば、焼成された辞書には{1,0}が含まれていますが、expectedSequence辞書には{0,1}。予想されるイベントを見ることで、これはexpectedSequenceキューに適しています。だから、実際には、あなたの最後のコードブロックに埋め込まれたキューはイベントハンドラの 'age'によって間違って構築されます。

私はあなたがこれまで

var subscriptions = subscribeActions.ToList(); 

    foreach (var firedIndex in fired) 
    { 

    if (firedIndex != expectedSequence.Dequeue()) 
    { 
     inOrder = false; 
     break; 
    } 

    executionIndex++; 
    Console.WriteLine("Execution index: {0}", executionIndex); 
    } 

から元

public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction, Queue<int> expectedSequence) 

方法で提供されているコードの中にある文を変更します。その後、

//When comparing indexes, you'll probably need to reverse the fired queue 
    fired = new Queue<int>(fired.Reverse()); 
    foreach (var firedIndex in fired) 
    { 

    if (firedIndex != expectedSequence.Dequeue()) 
    { 
     inOrder = false; 
     break; 
    } 

    executionIndex++; 
    Console.WriteLine("Execution index: {0}", executionIndex); 
    } 

テスト意志のすべてをあなたはこのスクリーンショットで見ることができるように完璧に渡します:

enter image description here

+0

私にとっては、「起動」インデックスには{1,1}が含まれています。あなたが正しいとはいえ、これは私が予期していなかった別のバグです。私は自分のコードで '.Reverse()'を使用します。 –

+0

こんにちは@NickUdell、あなたはNUnitからいくつかの出力を持っているのですか? – RvdV79

+0

残念ながら、それは多くの情報を与えていないUnityのラッパーの中で実行されているようです。 Unityライブラリからコードを抽出し、それを独自のソリューションで実行しようとします。 –

2

最初の部分は:はい、それは方法lambdas可変スコープと関係がありました。 Access to Modified Closureを参照してください。 私はそれを理解しようとしばらく時間を費やしていたので、私が使用したコード(すべてのテストが合格)を貼り付けることができます。

class Test 
{ 
    public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction) 
    { 
     var expectedSequence = new Queue<int>(); 
     for (int i = 0; i < subscribeActions.Count; i++) 
      expectedSequence.Enqueue(i); 
     ExpectEventSequence(subscribeActions, triggerAction, expectedSequence); 
    } 

    public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction, Queue<int> expectedSequence) 
    { 
     var fired = new Queue<int>(); 
     var subscriptions = subscribeActions.ToList(); 

     foreach (var subscription in subscriptions) 
     { 
      subscription((o, e) => 
      { 
       var index = subscriptions.IndexOf(subscription); 
       fired.Enqueue(index); 
      }); 
     } 
     triggerAction(); 
     var executionIndex = 0; 
     var inOrder = true; 
     foreach (var firedIndex in fired) 
     { 
      if (firedIndex != expectedSequence.Dequeue()) 
      { 
       inOrder = false; 
       break; 
      } 
      executionIndex++; 
     } 
     if (subscribeActions.Count != fired.Count) 
      Assert.Fail("Not all events were fired."); 
     if (!inOrder) 
      Assert 
       .Fail(string.Format(
       CultureInfo.CurrentCulture, 
       "Events were not fired in the expected sequence from element {0}", 
       executionIndex)); 
    } 
} 

public class Fueled 
{ 
    public event EventHandler<FuelEventArgs> FuelChanged = delegate { }; 
    public event EventHandler FuelEmpty = delegate { }; 
    public event EventHandler FuelFull = delegate { }; 
    public event EventHandler FuelNoLongerFull = delegate { }; 
    public event EventHandler FuelNoLongerEmpty = delegate { }; 
    private float fuel; 

    public float Fuel 
    { 
     get{ return fuel; } 
     private set 
     { 
      var adjustedFuel = Math.Max(0, Math.Min(value, MaxFuel)); 

      if (fuel != adjustedFuel) 
      { 
       var oldFuel = fuel; 
       fuel = adjustedFuel; 
       RaiseCheckFuelChangedEvents(oldFuel); 
      } 
     } 
    } 

    public void FillFuel() 
    { 
     Fuel = MaxFuel; 
    } 

    public float MaxFuel { get; set; } 

    private void RaiseCheckFuelChangedEvents(float oldFuel) 
    { 
     FuelChanged(this, new FuelEventArgs(oldFuel, Fuel)); 

     if (fuel == 0) 
      FuelEmpty(this, EventArgs.Empty); 
     else if (fuel == MaxFuel) 
      FuelFull(this, EventArgs.Empty); 
     if (oldFuel == 0 && Fuel != 0) 
      FuelNoLongerEmpty(this, EventArgs.Empty); 
     else if (oldFuel == MaxFuel && Fuel != MaxFuel) 
      FuelNoLongerFull(this, EventArgs.Empty); 
    } 
} 

public class FuelEventArgs : EventArgs 
{ 
    public FuelEventArgs(float oldFuel, float fuel) 
    { 
    } 
} 

[TestFixture] 
public class Tests 
{ 
    [Test()] 
    public void FillFuel_Test([Values(1, 5, 10, 100)]float maxFuel) 
    { 
     var fuelTank = new Fueled() 
     { 
      MaxFuel = maxFuel 
     }; 
     var eventHandlerSequence = new Queue<Action<EventHandler>>(); 
     //Dealing with a subclass of EventHandler 
     eventHandlerSequence.Enqueue(x => fuelTank.FuelChanged += (o, e) => x(o, e)); 
     eventHandlerSequence.Enqueue(x => fuelTank.FuelFull += x); 
     Test.ExpectEventSequence(eventHandlerSequence,() => fuelTank.FillFuel()); 
    } 
} 

基本的には、テスト方法で予想されるイベントの順序を変更しました。ループを変更した後でもまだ間違った結果が得られている場合、問題は貼り付けられたコードスコープ外でなければならないと思います。私はVS 2013のコミュニティ+ ReSharperの8、NUnitのを使用してい2.6.4.14350

編集:別のアプローチ

私はあなたが実際に掲載の問題を解決しようとしていたが、多分これは実際にあなたが望むものになります。 あなたはあなたのアプローチの簡易版を試して考えていない?:

[Test()] 
public void FillFuel_Test([Values(1, 5, 10, 100)]float maxFuel) 
{ 
    var fuelTank = new Fueled() 
    { 
     MaxFuel = maxFuel 
    }; 
    var expectedEventSequence = new[] 
    { 
     "FuelChanged", 
     "FuelFull" 
    }; 
    var triggeredEventSequence = new List<string>(); 
    fuelTank.FuelChanged += (o, e) => triggeredEventSequence.Add("FuelChanged"); 
    fuelTank.FuelFull += (o, e) => triggeredEventSequence.Add("FuelFull"); 

    fuelTank.FillFuel(); 

    Assert.AreEqual(expectedEventSequence,triggeredEventSequence); 
} 
関連する問題