Pertanyaan Bagaimana cara menguji metode Aksi yang mengembalikan JsonResult?


Jika saya memiliki kontroler seperti ini:

[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);
}

Pada dasarnya, saya mengambil barang dari repositori saya, lalu memproyeksikannya ke dalam List<T> tipe anonim.

Bagaimana saya bisa mengujinya?

System.Web.Mvc.JsonResult memiliki properti yang disebut Data, tapi itu tipe object, seperti yang kami harapkan.

Jadi apakah itu berarti jika saya ingin menguji bahwa objek JSON memiliki properti yang saya harapkan ("id", "name", "type"), saya harus menggunakan refleksi?

EDIT:

Inilah tes saya:

// 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.");
}

Tapi saya mendapatkan error runtime dalam loop, menyatakan "objek tidak mengandung definisi untuk id".

Ketika saya breakpoint, actionResult.Data didefinisikan sebagai List<T> dari jenis anonim, jadi saya pikir jika saya menyebutkan melalui ini, saya dapat memeriksa properti. Di dalam lingkaran, objek tidak memiliki properti yang disebut "id" - jadi tidak yakin apa masalahnya.


40
2018-02-14 06:36


asal


Jawaban:


RPM, Anda terlihat benar. Saya masih harus banyak belajar dynamic dan saya tidak bisa mendapatkan pendekatan Marc untuk bekerja baik. Jadi di sini adalah bagaimana saya melakukannya sebelumnya. Anda mungkin merasa terbantu. Saya baru saja menulis metode ekstensi sederhana:

    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);
    }

Maka saya hanya menggunakan itu untuk melakukan pernyataan pada data JSON saya:

        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));

15
2018-02-16 03:05



Saya tahu saya agak terlambat pada orang-orang ini, tetapi saya menemukan mengapa solusi dinamis tidak berfungsi:

JsonResult mengembalikan objek anonim dan ini, secara default, internal, sehingga mereka perlu dibuat terlihat oleh proyek pengujian.

Buka proyek aplikasi ASP.NET MVC Anda dan temukan AssemblyInfo.cs dari folder bernama Properties. Buka AssemblyInfo.cs dan tambahkan baris berikut ke bagian akhir file ini.

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

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

Saya pikir akan menyenangkan untuk memiliki yang satu ini untuk catatan. Bekerja seperti pesona


50
2018-03-24 22:11



Saya agak terlambat ke pesta, tetapi saya membuat bungkus kecil yang memungkinkan saya menggunakannya dynamic properti. Pada jawaban ini saya punya ini bekerja pada ASP.NET Core 1.0 RC2, tapi saya percaya jika Anda mengganti resultObject.Value dengan resultObject.Data seharusnya berfungsi untuk versi non-inti.

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;
    }
}

Penggunaan, dengan asumsi pengontrol berikut:

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

Tes (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);

6
2018-06-13 09:20



Saya memperluas solusi dari Matt Greer dan datang dengan ekstensi kecil ini:

    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;
    }

Dan saya hanya menjalankan unittest seperti ini: - Atur hasil data yang diharapkan:

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

- Tegaskan hasilnya:

        // Assert
        result.IsJson().WithModel(expected);

1
2017-07-23 08:26



Inilah yang saya gunakan, mungkin itu berguna bagi siapa saja. Ini menguji tindakan yang mengembalikan objek JSON untuk digunakan dalam fungsi clientside. Ini menggunakan Moq dan 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);
}

1
2017-11-09 07:38



Solusi saya adalah menulis metode ekstensi:

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);
        }
    }
}

1
2018-02-29 20:57



Jika dalam tes Anda tahu persis apa hasil data JSON seharusnya maka Anda bisa melakukan sesuatu seperti ini:

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

P.S. Ini akan menjadi jika Anda telah menggunakan FluentAssertions.Mvc5 - tetapi seharusnya tidak sulit untuk mengubahnya ke alat pengujian apa pun yang Anda gunakan.


0
2018-06-30 14:05