web-dev-qa-db-ja.com

単体テストのためのHttpPostedFileBaseとInputStreamのモック

次のコード行をテストしたいと思います。

...
Bitmap uploadedPicture = Bitmap.FromStream(model.Picture.InputStream) as Bitmap;
...

Pictureは、私のモデルタイプHttpPostedFileBaseのプロパティです。ユニットテスト用にHttpPostedFileBaseプロパティをモックしたいと思います。

model.Picture = new Mock<HttpPostedFileBase>().Object;

全く問題無い。

ここで、InputStreamをモックする必要があります。そうしないと、nullになります。

model.Picture.InputStream = new Mock<Stream>().Object;

InputStreamが読み取り専用であるため、これは機能していません(setterメソッドがないため)。

public virtual Stream InputStream { get; }

この問題を処理するための適切でクリーンな方法はありますか? 1つの解決策は、ユニットテストの派生クラスでHttpPostedFileBaseをオーバーライドすることです。他のアイデアはありますか?

22
mosquito87

こんにちは:)私は次のようなことをしました

    [TestInitialize]
    public void SetUp()
    {
        _stream = new FileStream(string.Format(
                        ConfigurationManager.AppSettings["File"],
                        AppDomain.CurrentDomain.BaseDirectory), 
                     FileMode.Open);

        // Other stuff
    }

そしてテスト自体では、

    [TestMethod]
    public void FileUploadTest() 
    {
        // Other stuff

        #region Mock HttpPostedFileBase

        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var files = new Mock<HttpFileCollectionBase>();
        var file = new Mock<HttpPostedFileBase>();
        context.Setup(x => x.Request).Returns(request.Object);

        files.Setup(x => x.Count).Returns(1);

        // The required properties from my Controller side
        file.Setup(x => x.InputStream).Returns(_stream);
        file.Setup(x => x.ContentLength).Returns((int)_stream.Length);
        file.Setup(x => x.FileName).Returns(_stream.Name);

        files.Setup(x => x.Get(0).InputStream).Returns(file.Object.InputStream);
        request.Setup(x => x.Files).Returns(files.Object);
        request.Setup(x => x.Files[0]).Returns(file.Object);

        _controller.ControllerContext = new ControllerContext(
                                 context.Object, new RouteData(), _controller);

        // The rest...
    }

これがあなたのソリューションにアイデアを提供できることを願っています:)

35
TiagoC13

私はちょうど似たようなことに取り組んでいて、@ TiagoC13の答えに以下を追加したいと思いました。

テスト対象のシステムは、私が作成しているファイルサービスでした。要件の1つは、ファイルのサイズが正しいことをテストすることです。ハードコードされたファイル名に注意してください。これは、私のテストプロジェクトにフォルダとファイルとして存在します。ファイルのプロパティは次のとおりです。ビルドアクション:埋め込みリソースと出力ディレクトリへのコピー:新しい場合はコピー(ただし、常にコピーは正常に機能するはずです)

プロジェクトがビルドされると、testimage.jpgとそのフォルダーがビンに追加され、テストで検出されます。

FileStream.Close();にも注意してください。これによりファイルが解放されるため、同じスイートで同様のテストを多数実行できます。

これがお役に立てば幸いです。

using Moq;
using NUnit.Framework;
using System.Web;

    [Test]
    public void IsValidFile() {
        string filePath = Path.GetFullPath(@"testfiles\testimage.jpg");
        FileStream fileStream = new FileStream(filePath, FileMode.Open);
        Mock<HttpPostedFileBase> uploadedFile = new Mock<HttpPostedFileBase>();

        uploadedFile
            .Setup(f => f.ContentLength)
            .Returns(10);

        uploadedFile
            .Setup(f => f.FileName)
            .Returns("testimage.jpg");

        uploadedFile
            .Setup(f => f.InputStream)
            .Returns(fileStream);

        var actual = fileSystemService.IsValidImage(uploadedFile.Object, 720, 960);

        Assert.That(actual, Is.True);

        fileStream.Close();
    }
14

ディスク上のファイルを開いてストリームを作成する必要はありません。実際、それはかなり恐ろしい解決策だと思います。動作するテストストリームは、メモリ内で簡単に作成できます。

var postedFile = new Mock<HttpPostedFileBase>();

using (var stream = new MemoryStream())
using (var bmp = new Bitmap(1, 1))
{
    var graphics = Graphics.FromImage(bmp);
    graphics.FillRectangle(Brushes.Black, 0, 0, 1, 1);
    bmp.Save(stream, ImageFormat.Jpeg);

    postedFile.Setup(pf => pf.InputStream).Returns(stream);

    // Assert something with postedFile here   
}        
9