3

元の質問は次のとおり です。AutoFixtureを使用したHtmlヘルパーのユニットテスト

元の質問を再度開く必要があるかどうかわかりません。ただし、元の質問を解決済みとしてマークしたため、新しい質問を作成することにしました。私がこれを間違っていた場合はお詫び申し上げます。

マークの提案したアプローチを使用していましたが、フリーズを使用しているときに行き詰まりました。

以下は完全なソースコードです... テスト中のクラス:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcDemo2.Helpers
{
      public static class Keys
      {
          public static readonly string SomeKey = "SomeKey";
      }

      public static class SampleHelpers
      {
          public static MvcHtmlString SampleTable(this HtmlHelper helper, 
            SampleModel model, IDictionary<string, object> htmlAttributes)
          {
                if (helper == null)
                {
                    throw new ArgumentNullException("helper");
                }

                if (model == null)
                {
                    throw new ArgumentNullException("model");
                }

                TagBuilder tagBuilder = new TagBuilder("table");
                tagBuilder.MergeAttributes(htmlAttributes);                               
                tagBuilder.GenerateId(helper.ViewContext.
                                 HttpContext.Items[Keys.SomeKey].ToString());
                return MvcHtmlString.Create(
                         tagBuilder.ToString(TagRenderMode.Normal));
            }
      }
  }


  public class SampleModel
  {
  }
}

単体テストは、HttpContext 内の指定されたキーに対して期待どおりに返される Html を確認することです。

public void SampleTableHtmlHelper_WhenKeyExistWithinHttpContext_ReturnsExpectedHtml()

以下のようにフィクスチャを構成しました

var fixture = new Fixture().Customize(new AutoMoqCustomization());

次に、ViewContext でフリーズします。

var vc = fixture.Freeze<ViewContext>();

以下の例外が発生します。

エラー 1 テスト 'MvcDemo2.Tests.Controllers.SampleHelpersTestsAutoFixture.SampleTableHtmlHelper_WhenKeyExistWithinHttpContext_ReturnsExpectedHtml' が失敗しました: System.Reflection.TargetInvocationException : 呼び出しのターゲットによって例外がスローされました。---- System.NotImplementedException : メソッドまたは操作が実装されていません。System.RuntimeMethodHandle._InvokeMethodFast (IRuntimeMethodInfo メソッド、オブジェクト ターゲット、Object[] 引数、SignatureStruct& sig、MethodAttributes methodAttributes、RuntimeType typeOwner) で System.RuntimeMethodHandle.InvokeMethodFast (IRuntimeMethodInfo メソッド、オブジェクト ターゲット、Object[] 引数、シグネチャ sig、MethodAttributes methodAttributes 、RuntimeType typeOwner) System.Reflection.RuntimeMethodInfo.Invoke(Object obj、BindingFlags invokeAttr、バインダー バインダー、
System.Reflection.RuntimePropertyInfo.SetValue (オブジェクト obj、オブジェクト値、BindingFlags invokeAttr、バインダー バインダー、オブジェクト [] インデックス、CultureInfo カルチャ) で System.Reflection.RuntimePropertyInfo.SetValue (オブジェクト obj、オブジェクト値、オブジェクト [] インデックス) でPloeh.AutoFixture.Kernel.AutoPropertiesCommand 1.Create 1.Execute(T specimen, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.<>c__DisplayClass6.b__1(ISpecimenBuilder b) at System.Linq.Enumerable.WhereSelectListIterator 2.MoveNext() at System .Linq.Enumerable.d__a52.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator

1.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable
1 ソース) Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(オブジェクト要求、ISpecimenContext コンテキスト) で Ploeh.AutoFixture.Kernel.RecursionGuard.Create(オブジェクト要求、ISpecimenContext コンテキスト) で Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(オブジェクト要求) ) at Ploeh.AutoFixture.Kernel.SeedIgnoringRelay.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.<>c__DisplayClass6.b__1(ISpecimenBuilder b) at System.Linq.Enumerable.WhereSelectListIterator 2.MoveNext() at System.Linq.Enumerable.d__a5 1 ソース) Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create (オブジェクト要求、ISpecimenContext コンテキスト) で Ploeh.AutoFixture.Kernel.Postprocessor 2.MoveNext()2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator

1.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable
1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.<>c__DisplayClass6.<Create>b__1(ISpecimenBuilder b) at System.Linq.Enumerable.WhereSelectListIterator
System.Linq.Enumerable.WhereSelectEnumerableIterator 1.MoveNext() で System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable 2 スコープ、HttpContextBase httpContext) で System.Web.Mvc.ViewContext.SetClientValidationEnabled(ブール値が有効、IDictionary`2 スコープ) 、HttpContextBase httpContext) で System.Web.Mvc.ViewContext.set_ClientValidationEnabled(ブール値) C:\Users... 78 2.MoveNext()
at System.Linq.Enumerable.<DefaultIfEmptyIterator>d__a5

1 source) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request) at Ploeh.AutoFixture.SpecimenFactory.CreateAnonymous[T](ISpecimenContext context, T seed) at Ploeh.AutoFixture.SpecimenFactory.CreateAnonymous[T](ISpecimenBuilderComposer composer, T seed) at Ploeh.AutoFixture.FixtureFreezer.Freeze[T](IFixture fixture, T seed)
at MvcDemo2.Tests.Controllers.SampleHelpersTestsAutoFixture.SampleTableHtmlHelper_WhenKeyExistWithinHttpContext_ReturnsExpectedHtml() in C:\Users\...:line 78 ----- Inner Stack Trace ----- at System.Web.HttpContextBase.get_Items() at System.Web.Mvc.ViewContext.ScopeCache.Get(IDictionary

プロパティViewContext.SetClientValidationEnabledの値を設定しようとすると失敗するようです。

私はこれにこだわっています。どんな考えでも大歓迎です。

4

3 に答える 3

5

内部スタック トレースを検討すると、例外が によってスローされていることがわかりますHttpContextBase.Items。リフレクション ツールを使用して実装を調べると、この仮想メソッドが NotImplementedException をスローすることがわかります - POLA 違反について話してください。BCL の Web 抽象化の多くはまさにそれを行いますが、これを処理するのは非常に困難です。

それがさらに役立つかどうかはわかりませんが、次のように ViewContext クラスの AutoProperties をオフにすることで、この特定の問題を回避できます。

fixture.Customize<ViewContext>(c => c.OmitAutoProperties());
于 2011-09-12T13:41:45.863 に答える
0

ありがとうマーク。AutoFixture は非常に便利ですが、MVC の単体テストを行うと、API の適用が少し難しくなります。おそらく、私がまだ API に慣れていないためです。

と…。

  fixture.Customize<ViewContext>(c => c.OmitAutoProperties());
  var vc = fixture.Freeze<ViewContext>();

上記は正常に動作しますが、あなたが疑ったように、アイテムを追加しようとすると再び失敗します

  vc.HttpContext.Items.Add(Keys.SomeKey, "foo");

例外: メソッドまたは操作は実装されていません。

HttpContextBase のリフレクター...

  public virtual IDictionary Items
  {
     get
     {
         throw new NotImplementedException();
     }
  }

したがって、私が考えることができる唯一の方法は、HttpContextBase の独自の実装を作成することです

    private class FakeHttpContext : HttpContextBase
    {
        private Dictionary<object, object> _items = new Dictionary<object, object>();
        public override IDictionary Items { get { return _items; } }
    }

次に、以下は紛らわしいビットです..

   fixture.Inject<HttpContextBase>(new FakeHttpContext());
   var hc = fixture.CreateAnonymous<HttpContextBase>();

これらの 2 行を入れ替えると (最初に匿名インスタンスを作成し、次に偽のインスタンスを挿入すると)、エラーが発生します。

AutoFixture は System.Web.HttpContextBase からインスタンスを作成できませんでした。おそらく、パブリック コンストラクターがないためです。

これまでのところ、このようなテストを思いつくことができます...

    public void SampleTableHtmlHelper_WhenKeyExistWithinHttpContext_ReturnsExpectedHtml()
    {
        //Arrange
        var fixture = new Fixture(); 
        fixture.Customize<ViewContext>(c => c.OmitAutoProperties());
        var vc = fixture.Freeze<ViewContext>();
        fixture.Inject<HttpContextBase>(new FakeHttpContext());
        var hc = fixture.CreateAnonymous<HttpContextBase>();

        vc.HttpContext = hc;
        vc.HttpContext.Items.Add(Keys.SomeKey, "foo");

        var htmlHelper = fixture.CreateAnonymous<HtmlHelper>();
        var sampleModel = fixture.CreateAnonymous<SampleModel>();

        //Act
        var result = SampleHelpers.SampleTable(htmlHelper, sampleModel, null).ToString();

        //Assert
        Assert.Equal("<table id=\"foo\"></table>", result);
    }

また、テストに影響がないように見えるため、new AutoMoqCustomization() を削除しました。AutoFixture に慣れたら、より良いバージョンを思いつくことができるかもしれません。助けてくれてありがとう。

于 2011-09-14T11:55:30.813 に答える