2017-11-15 116 views
2

IFormFileのリストを自分の任意のデータベースファイルクラスのリストに変換する非同期関数の単体テストに取り組んでいます。c#mocking IFormFile CopyToAsync()メソッド

バイト配列にファイルデータを変換する方法であって、それはmockableなるよう

internal async Task<List<File>> ConvertFormFilesToFiles(ICollection<IFormFile> formFiles) 
{ 
    var file = new File 
    { 
     InsertDateTime = DateTime.Now, 
     LastChangeDateTime = DateTime.Now 
    }; 
    if (formFile.Length > 0) 
    { 
     using (var memoryStream = new MemoryStream()) 
     { 
      await formFile.CopyToAsync(memoryStream, CancellationToken.None); 
      file.FileData = memoryStream.ToArray(); 
     } 
    } 
    // ... 
} 

関数はIFormFilesのいるICollectionを受信します。今の

私はこのようなテストコードしている:関数は、新しい空のMemoryStream(私はこれが必要なのかはわからない)とCopyToAsyncメソッドを呼び出すため

//Arrange 
var fileConverter = new FilesConverter(); 
using (var fileStream = new FileStream("Files/uploadme.txt", FileMode.Open, FileAccess.Read)) 
{ 
    using (var memoryStream = new MemoryStream()) 
    { 
     var newMemoryStream = new MemoryStream(); 
     fileStream.CopyTo(memoryStream); 
     FormFileMock.Setup(f => f.CopyToAsync(newMemoryStream, CancellationToken.None)).Returns(Task.CompletedTask); 
     // some other setups 

     //Act 
     var result = await fileConverter.ConvertFormFilesToFiles(new List<IFormFile> { FormFileMock.Object }); 
     //Assert 
     Assert.IsTrue(result.Any()); 
    } 
} 

newMemoryStream変数が作成されます。

問題は、がformFile.CopyToAsync(memoryStream、CancellationToken.None)を待つことです。はmemoryStreamにデータをコピーしません。

+1

質問を再確認し、[mcve]であることを確認してください。いくつかのタイプミスがあります。 – Nkosi

+0

また、あなたの設定に従って。何も実際にコピーされません。完了した状態に戻るようにコールを設定するだけです。実際の機能は実装されていません。戻る前に、いくつかの機能を実行するためにコールバックを追加する必要があります。 – Nkosi

+0

@ Nkosiコードを最小限にするためにコードを削除しました。これは良いですか? – Jeroen

答えて

2

私は@Nkosiと@nvoigtの回答を組み合わせました。 @nofigtが指摘しているように、実際のファイルへのアクセスは、実際には "ユニット"テストではありません。だから私はこのようにバイト配列にファイルを置き換えました:

using (var memoryStream = new MemoryStream(new byte[]{1,2,3,4})) 

完全なファイルの代わりに。 @Nkosi

FormFileMock.Setup(f => f.CopyToAsync(It.IsAny<Stream>(), CancellationToken.None)) 
    .Callback<Stream, CancellationToken>((stream, token) => 
    { 
     // with memoryStream being the stream from inside the using statement 
     memoryStream.CopyTo(stream); 
    }).Returns(Task.CompletedTask); 

そして今、それが機能することで示唆したように

そして、私は嘲笑オブジェクト上.callbackを実施しました。

3

await formFile.CopyToAsync(memoryStream, CancellationToken.None)は、memoryStreamにデータをコピーしないという問題があります。

あなたの設定に従って。実際には何もコピーされません。

完了したとして戻るようにコールを設定するだけです。実際の機能は実装されていません。

タスクを返す前に、いくつかの機能を実行するには、Callbackを追加する必要があります。

FormFileMock 
    .Setup(_ => _.CopyToAsync(It.IsAny<Stream>(), CancellationToken.None)) 
    .Callback<Stream, CancellationToken>((stream, token) => { 
     //memory stream in this scope is the one that was populated 
     //when you called **fileStream.CopyTo(memoryStream);** in the test 
     memoryStream.CopyTo(stream); 
    }) 
    .Returns(Task.CompletedTask); 
+0

これは動作しますが、私はこの答えを@nvoigtと一緒に答えました。 – Jeroen

+0

問題が解決したら私はあなたがそれらの1つを受け入れることをお勧めします。彼の方がいいよIMHO – Nkosi

3

私はモックフレームワークを使用すると、これらの日「の」完全であるが、なぜ単に枠組みこと枠組みを離れて、シンプルで簡単な方法を行っていないので、これは不評かもしれません知っていますか? FormFileを作成することはできません。ちょうど実際の取引:

var fileConverter = new FilesConverter(FilesConverterLoggerMock.Object, FileDataMock.Object); 

// access to a real file should really not be in a "unit" test, but anyway: 
using (var stream = new MemoryStream(File.ReadAllBytes("Files/uploadme.txt")) 
{ 
    // create a REAL form file 
    var formFile = new FormFile(stream , 0, stream.Length, "name", "filename"); 

    //Act 
    var result = await fileConverter.ConvertFormFilesToFiles(new List<IFormFile> { formFile }); 

    //Assert 
    Assert.IsTrue(result.Any()); 
} 
+0

これは良い答えです。これは模擬練習のすべての複雑さを取り除きます。きれいで、シンプルで、仕事を終わらせる。 – Nkosi

+0

これは動作しますが、私はこの答えを@Nkosiの答えと組み合わせました。 – Jeroen