47

私がこのようなコントローラーを持っている場合:

[HttpPost]
public JsonResult FindStuff(string query) 
{
   var results = _repo.GetStuff(query);
   var jsonResult = results.Select(x => new
   {
      id = x.Id,
      name = x.Foo,
      type = x.Bar
   }).ToList();

   return Json(jsonResult);
}

基本的に、私は自分のリポジトリから何かを取得し、それList<T>を匿名タイプに投影します。

どうすればユニットテストできますか?

System.Web.Mvc.JsonResultと呼ばれるプロパティがありますが、予想どおり、Dataタイプはです。object

つまり、JSONオブジェクトに期待するプロパティ( "id"、 "name"、 "type")があることをテストする場合は、リフレクションを使用する必要がありますか?

編集:

これが私のテストです:

// Arrange.
const string autoCompleteQuery = "soho";

// Act.
var actionResult = _controller.FindLocations(autoCompleteQuery);

// Assert.
Assert.IsNotNull(actionResult, "No ActionResult returned from action method.");
dynamic jsonCollection = actionResult.Data;
foreach (dynamic json in jsonCollection)
{
   Assert.IsNotNull(json.id, 
       "JSON record does not contain \"id\" required property.");
   Assert.IsNotNull(json.name, 
       "JSON record does not contain \"name\" required property.");
   Assert.IsNotNull(json.type, 
       "JSON record does not contain \"type\" required property.");
}

しかし、ループで「オブジェクトにidの定義が含まれていません」というランタイムエラーが発生します。

ブレークポイントが匿名型actionResult.Dataとして定義されているList<T>場合、これらを列挙すると、プロパティを確認できます。ループ内では、オブジェクトに「id」というプロパティがあります。そのため、問題が何であるかはわかりません。

4

8 に答える 8

57

私はこの人たちに少し遅れていることを知っていますが、動的ソリューションが機能しなかった理由を見つけました:

JsonResult匿名オブジェクトを返します。これらはデフォルトでinternalであるため、テストプロジェクトで表示できるようにする必要があります。

ASP.NET MVCアプリケーションプロジェクトを開き、AssemblyInfo.cs[プロパティ]というフォルダーから検索します。AssemblyInfo.csを開き、このファイルの最後に次の行を追加します。

[assembly: InternalsVisibleTo("MyProject.Tests")]

引用元: http ://weblogs.asp.net/gunnarpeipman/archive/2010/07/24/asp-net-mvc-using-dynamic-type-to-test-controller-actions-returning-jsonresult.aspx

これがレコードにあるといいなと思いました。チャームのように機能します

于 2011-03-24T22:11:37.013 に答える
19

RPM、あなたは正しいように見えます。私はまだ学ぶことがたくさんdynamicあり、マークのアプローチを機能させることもできません。これが私が以前やっていた方法です。あなたはそれが役に立つと思うかもしれません。簡単な拡張メソッドを作成しました。

    public static object GetReflectedProperty(this object obj, string propertyName)
    {  
        obj.ThrowIfNull("obj");
        propertyName.ThrowIfNull("propertyName");

        PropertyInfo property = obj.GetType().GetProperty(propertyName);

        if (property == null)
        {
            return null;
        }

        return property.GetValue(obj, null);
    }

次に、それを使用してJsonデータに対してアサーションを実行します。

        JsonResult result = controller.MyAction(...);
                    ...
        Assert.That(result.Data, Is.Not.Null, "There should be some data for the JsonResult");
        Assert.That(result.Data.GetReflectedProperty("page"), Is.EqualTo(page));
于 2011-02-16T03:05:25.523 に答える
9

パーティーに少し遅れましたが、dynamicプロパティを使用できるようにする小さなラッパーを作成しました。この回答の時点で、これはASP.NET Core 1.0 RC2で機能していますが、これに置き換えるresultObject.ValueresultObject.Data、非コアバージョンでも機能するはずです。

public class JsonResultDynamicWrapper : DynamicObject
{
    private readonly object _resultObject;

    public JsonResultDynamicWrapper([NotNull] JsonResult resultObject)
    {
        if (resultObject == null) throw new ArgumentNullException(nameof(resultObject));
        _resultObject = resultObject.Value;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (string.IsNullOrEmpty(binder.Name))
        {
            result = null;
            return false;
        }

        PropertyInfo property = _resultObject.GetType().GetProperty(binder.Name);

        if (property == null)
        {
            result = null;
            return false;
        }

        result = property.GetValue(_resultObject, null);
        return true;
    }
}

次のコントローラーを想定した使用法:

public class FooController : Controller
{
    public IActionResult Get()
    {
        return Json(new {Bar = "Bar", Baz = "Baz"});
    }
}

テスト(xUnit):

// Arrange
var controller = new FoosController();

// Act
var result = await controller.Get();

// Assert
var resultObject = Assert.IsType<JsonResult>(result);
dynamic resultData = new JsonResultDynamicWrapper(resultObject);
Assert.Equal("Bar", resultData.Bar);
Assert.Equal("Baz", resultData.Baz);
于 2016-06-13T09:20:18.620 に答える
2

これが私が使っているものです、おそらくそれは誰にとっても役に立つでしょう。クライアントサイド機能で使用するJSONオブジェクトを返すアクションをテストします。MoqとFluentAssertionsを使用します。

[TestMethod]
public void GetActivationcode_Should_Return_JSON_With_Filled_Model()
{
    // Arrange...
    ActivatiecodeController activatiecodeController = this.ActivatiecodeControllerFactory();
    CodeModel model = new CodeModel { Activation = "XYZZY", Lifespan = 10000 };
    this.deviceActivatieModelBuilder.Setup(x => x.GenereerNieuweActivatiecode()).Returns(model);

    // Act...
    var result = activatiecodeController.GetActivationcode() as JsonResult;

    // Assert...
    ((CodeModel)result.Data).Activation.Should().Be("XYZZY");
    ((CodeModel)result.Data).Lifespan.Should().Be(10000);
}
于 2015-11-09T07:38:07.230 に答える
1

Matt Greerのソリューションを拡張して、この小さな拡張機能を考え出します。

    public static JsonResult IsJson(this ActionResult result)
    {
        Assert.IsInstanceOf<JsonResult>(result);
        return (JsonResult) result;
    }

    public static JsonResult WithModel(this JsonResult result, object model)
    {
        var props = model.GetType().GetProperties();
        foreach (var prop in props)
        {
            var mv = model.GetReflectedProperty(prop.Name);
            var expected = result.Data.GetReflectedProperty(prop.Name);
            Assert.AreEqual(expected, mv);
        }
        return result;
    }

そして、私は次のようにユニットテストを実行します:-期待されるデータ結果を設定します:

        var expected = new
        {
            Success = false,
            Message = "Name is required"
        };

-結果をアサートします:

        // Assert
        result.IsJson().WithModel(expected);
于 2014-07-23T08:26:08.753 に答える
1

私の解決策は、拡張メソッドを作成することです。

using System.Reflection;
using System.Web.Mvc;

namespace Tests.Extensions
{
    public static class JsonExtensions
    {
        public static object GetPropertyValue(this JsonResult json, string propertyName)
        {
            return json.Data.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public).GetValue(json.Data, null);
        }
    }
}
于 2016-02-29T20:57:32.007 に答える
0

テストでJsonデータの結果が正確にどうあるべきかがわかっている場合は、次のようにすることができます。

result.Data.ToString().Should().Be(new { param = value}.ToString());

PSこれは、FluentAssertions.Mvc5を使用した場合ですが、使用するテストツールに変換するのは難しいことではありません。

于 2017-06-30T14:05:28.603 に答える
0

これが私がそれを主張する方法です

foreach (var item in jsonResult.Data as dynamic) {
    ((int)item.Id).ShouldBe( expected Id value );
    ((string)item.name).ShouldBe( "expected name value" );
}
于 2019-04-24T09:17:48.667 に答える