2017-10-26 20 views
1

私はRabbitMQキューにメッセージをプッシュする.netコアAPIを作成しました。私はIOptionsを使用して、.jsonファイルから構成データを読み込み、それを依存関係として追加しました。以下はユニットテストRabbitMQ push with C# - .Net Core

は私のコントローラのコードです:

[Route("api/[controller]")] 
public class RestController : Controller 
{ 
    private RabbitMQConnectionDetail _connectionDetail; 

    public RestController(IOptions<RabbitMQConnectionDetail> connectionDetail) 
    { 
     _connectionDetail = connectionDetail.Value; 
    } 

    [HttpPost] 
    public IActionResult Push([FromBody] OrderItem orderItem) 
    { 
     try 
     { 
      using (var rabbitMQConnection = new RabbitMQConnection(_connectionDetail.HostName, 
       _connectionDetail.UserName, _connectionDetail.Password)) 
      { 
       using (var connection = rabbitMQConnection.CreateConnection()) 
       { 
        var model = connection.CreateModel(); 
        var helper = new RabbitMQHelper(model, "Topic_Exchange"); 
        helper.PushMessageIntoQueue(orderItem.Serialize(), "Order_Queue"); 
       } 
      } 
     } 
     catch (Exception) 
     { 
      return StatusCode((int)HttpStatusCode.BadRequest); 
     } 
     return Ok(); 
    } 
} 

接続の詳細クラスは以下のプロパティ

public class RabbitMQConnectionDetail 
{ 
    public string HostName { get; set; } 

    public string UserName { get; set; } 

    public string Password { get; set; } 
} 

は今、私はそれをテストユニットにしたいたが、私はに対してそれをテストするつもりですので、ブラックボックス、私はそれを単体テストする方法と親切な助けを求めることを考えることができません。

ConnectionClass

public class RabbitMQConnection : IDisposable 
{ 
    private static IConnection _connection; 
    private readonly string _hostName; 
    private readonly string _userName; 
    private readonly string _password; 

    public RabbitMQConnection(string hostName, string userName, string password) 
    { 
     _hostName = hostName; 
     _userName = userName; 
     _password = password; 
    } 

    public IConnection CreateConnection() 
    { 
     var _factory = new ConnectionFactory 
     { 
      HostName = _hostName, 
      UserName = _userName, 
      Password = _password 
     }; 
     _connection = _factory.CreateConnection(); 
     var model = _connection.CreateModel(); 

     return _connection; 
    } 

    public void Close() 
    { 
     _connection.Close(); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      _connection.Close(); 
     } 
    } 

    ~ RabbitMQConnection() 
    { 
     Dispose(false); 
    } 
} 

ヘルパークラス

public class RabbitMQHelper 
{ 
    private static IModel _model; 
    private static string _exchangeName; 
    const string RoutingKey = "dummy-key."; 

    public RabbitMQHelper(IModel model, string exchangeName) 
    { 
     _model = model; 
     _exchangeName = exchangeName; 
    } 


    public void SetupQueue(string queueName) 
    { 
     _model.ExchangeDeclare(_exchangeName, ExchangeType.Topic); 
     _model.QueueDeclare(queueName, true, false, false, null); 
     _model.QueueBind(queueName, _exchangeName, RoutingKey); 
    } 

    public void PushMessageIntoQueue(byte[] message, string queue) 
    { 
     SetupQueue(queue); 
     _model.BasicPublish(_exchangeName, RoutingKey, null, message); 
    } 

    public byte[] ReadMessageFromQueue(string queueName) 
    { 
     SetupQueue(queueName); 
     byte[] message; 
     var data = _model.BasicGet(queueName, false); 
     message = data.Body; 
     _model.BasicAck(data.DeliveryTag, false); 
     return message; 
    } 
} 
+0

これらのテストでは、どんな種類のアサーションを書きたいと思っていますか? – NWard

+0

私はブラックボックスに対してテストしているので、どのアサーションが私を助けてくれるのか分かりません。 IsEqualは間違いなく助けにはならない。しかし、メッセージ数が増えたことを示すことができたり、インサートに次のアクションがあると、それが役立つかもしれません。 – Developer

+0

そのコントローラが正しいIActionResultを返すのをテストし、正しいメッセージがキューにプッシュされていることを確認する必要があります。 – Fabio

答えて

4

コントローラの実装上の懸念を強く抱かせると、コントローラのテストが難しくなります。あなたが提供したサンプルから、3番目のAPI実装をカプセル化しており、抽象化を公開していることがわかりました。良い。しかし、テストの際にそれらをモックする抽象化を作成していません。私はこれを可能にするためにRabbitMQConnectionのリファクタリングをお勧めします。

まず、バッキング抽象化を所有していますか?

public interface IRabbitMQConnectionFactory { 
    IConnection CreateConnection(); 
} 

そして

public class RabbitMQConnection : IRabbitMQConnectionFactory { 
    private readonly RabbitMQConnectionDetail connectionDetails; 

    public RabbitMQConnection(IOptions<RabbitMQConnectionDetail> connectionDetails) { 
     this.connectionDetails = connectionDetails.Value; 
    } 

    public IConnection CreateConnection() { 
     var factory = new ConnectionFactory { 
      HostName = connectionDetails.HostName, 
      UserName = connectionDetails.UserName, 
      Password = connectionDetails.Password 
     }; 
     var connection = factory.CreateConnection(); 
     return connection; 
    } 
} 

は、いくつかの時間を取り、このリファクタリングで行われた、まさに見直し、次のようにRabbitMQConnectionをリファクタリング。 IOptionsはコントローラーから工場に移され、RabbitMQConnectionも意図した目的で簡素化されました。接続の作成。

[コントローラは現在

[Route("api/[controller]")] 
public class RestController : Controller { 
    private readonly IRabbitMQConnectionFactory factory; 

    public RestController(IRabbitMQConnectionFactory factory) { 
     this.factory = factory; 
    } 

    [HttpPost] 
    public IActionResult Push([FromBody] OrderItem orderItem) { 
     try {     
      using (var connection = factory.CreateConnection()) { 
       var model = connection.CreateModel(); 
       var helper = new RabbitMQHelper(model, "Topic_Exchange"); 
       helper.PushMessageIntoQueue(orderItem.Serialize(), "Order_Queue"); 
       return Ok(); 
      } 
     } catch (Exception) { 
      //TODO: Log error message 
      return StatusCode((int)HttpStatusCode.BadRequest); 
     } 
    } 
} 

が再びコントローラの簡素化の点に注意してくださいだけでなく、リファクタリングする必要があります。これにより、テスト時にファクトリを偽装して注入することができ、拡張子によってRabbitMQHelperがモックを使用できるようになりました。依存関係や純粋なDIのために選択したモックフレームワークを使用することができます。

+0

投稿を確認して更新します。ポインタありがとうございます。 – Developer

+0

コードを修正しました。現在、嘲笑は実現可能です。また、接続オブジェクトとモデルオブジェクトは使用できません。それは – Developer

+0

@ParthoGanguly助けてうれしいことはうれしくありませんでした。 – Nkosi

0

私はそれがユニット・テスト・シナリオであると思ういけません。外部コンポーネント、つまりデータベースまたはメッセージキューでテストする場合は、統合テストとして行うことをお勧めします。

私たちが行うことは、コンポーネントSQLデータベースと紺碧のメッセージバスを持つサンドボックス環境を持つことです。このコンポーネントの状態を正しく設定するコードがあります。つまり、データベースをシードしてメッセージバスをクリアします。次に、環境をテストしてデータベースの状態やメッセージバスの数などを確認します。