【问题标题】:Testing JSON Results from MVC 4 C# Controller测试来自 MVC 4 C# 控制器的 JSON 结果
【发布时间】:2013-09-26 14:56:16
【问题描述】:

所以我有一个控制器,可以将 json 返回到我需要测试的视图中。我尝试使用具有动态数据类型的反射来访问列表的子属性,但我不断收到类似于“无法投射”错误的内容。基本上我在一个列表中有一个列表,我想访问和验证有关但我无法访问它的内容。有没有人在 MVC4 中测试过从他们的控制器返回的 json 并有建议?

代码:

// arrange
        var repositoryMock = new Mock<IEdwConsoleRepository>();
        var date = -1;
        var fromDate = DateTime.Today.AddDays(date);
        EtlTableHistory[] tableHistories =
            {
                new EtlTableHistory
                    {
                        Table = new Table(),
                        RelatedStatus = new BatchStatus(),
                        BatchId = 1
                    }
            };
        EtlBatchHistory[] batchHistories = { new EtlBatchHistory
                                             {
                                                 Status = new BatchStatus(),
                                                 TableHistories = tableHistories
                                             } };

        repositoryMock.Setup(repository => repository.GetBatchHistories(fromDate)).Returns((IEnumerable<EtlBatchHistory>)batchHistories);
        var controller = new EdwController(new Mock<IEdwSecurityService>().Object, repositoryMock.Object);

        // act
        ActionResult result = controller.BatchHistories(1);

        // assert
        Assert.IsInstanceOfType(result, typeof(JsonResult), "Result type was incorrect");
        var jsonResult = (JsonResult)result;
        var resultData = (dynamic)jsonResult.Data;
        var returnedHistories = resultData.GetType().GetProperty("batchHistories").GetValue(resultData, null);

        var returnedTableHistoriesType = returnedHistories.GetType();
        Assert.AreEqual(1, returnedTableHistoriesType.GetProperty("Count").GetValue(returnedHistories, null), "Wrong number of logs in result data");

【问题讨论】:

  • 我想从 batchHistories 中的 EtlBatchHistory 对象中获取“TableHistories”属性。
  • 您的 JSON 是什么样的,和/或生成它的代码是什么?而且您应该能够只使用var returnedHistories = resultData.batchHistories;,而无需反射(这就是dynamic 的用途)。 (Count 属性相同)
  • Json 看起来像:“{ batchHistories = System.Collections.Generic.List1[&lt;&gt;f__AnonymousType111[System.Int32,System.String,System.String,System.String,System.Int32,System. Nullable1[System.Int64],System.Nullable1[System.Int32],System.String,System.String,System.String,System.Collections.Generic.List1[&lt;&gt;f__AnonymousType09[System.String,System.String,System.Int32,System.Int32 ,System.String,System.String,System.String,System.String,System.String]]]] }"
  • 当我尝试直接从 resultData 访问 batchHistories 时,我得到一个 'object' does not contain a definition for 'batchHistories' 错误。
  • 你的 JSON 不是很好的数据序列化。看起来您是通过在 List&lt;T&gt; 上执行 ToString() 编写的。修复它。

标签: c# asp.net-mvc json unit-testing testing


【解决方案1】:

这是一个例子:

Controller:

    [HttpPost]
    public JsonResult AddNewImage(string buildingID, string desc)
    {
        ReturnArgs r = new ReturnArgs();

        if (Request.Files.Count == 0)
        {
            r.Status = 102;
            r.Message = "Oops! That image did not seem to make it!";
            return Json(r);
        }
        if (!repo.BuildingExists(buildingID))
        {
            r.Status = 101;
            r.Message = "Oops! That building can't be found!";
            return Json(r);
        }

        SaveImages(buildingID, desc);
        r.Status = 200;
        r.Message = repo.GetBuildingByID(buildingID).images.Last().ImageID;

        return Json(r);
    }

    public class ReturnArgs
    {
        public int Status { get; set; }
        public string Message { get; set; }
    }

Test:

    [TestMethod]
    public void AddNewImage_Returns_Error_On_No_File()
    {
        // Arrange
        ExtendedBuilding bld = repo.GetBuildings()[0];
        string ID = bld.Id;

        var fakeContext = new Mock<HttpContextBase>();
        var fakeRequest = new Mock<HttpRequestBase>();

        fakeContext.Setup(cont => cont.Request).Returns(fakeRequest.Object);
        fakeRequest.Setup(req => req.Files.Count).Returns(0);

        BuildingController noFileController = new BuildingController(repo);
        noFileController.ControllerContext = new ControllerContext(fakeContext.Object, new System.Web.Routing.RouteData(), noFileController);

        // Act
        var result = noFileController.AddNewImage(ID, "empty");

        ReturnArgs data = (ReturnArgs)(result as JsonResult).Data;

        // Assert
        Assert.IsTrue(data.Status == 102);
    }

在您的示例中,我认为问题出在此处:

var resultData = (dynamic)jsonResult.Data;
var returnedHistories = resultData.GetType().GetProperty("batchHistories").GetValue(resultData, null);

resultData 对象将是您在操作中返回的对象的确切类型。所以如果你做了类似的事情:

List<String> list = repo.GetList();
return Json(list);

那么你的 resultData 将是以下类型:

List<String>

尝试确保您使用 Json(obj) 函数返回您的对象。

【讨论】:

  • 感谢您的帖子!我目前正在使用 Json(obj) 函数,从我的控制器返回一个 ActionResult 对象,它是一个 System.Web.Mvc.JsonResult (在该命名空间上可能是错误的,但它接近那个),在使用反射后我得到了batchHistory 属性是 BatchHistory 对象的匿名列表。其中是另一个匿名列表,但我无法通过反射访问任何一个,并且由于某种原因我可以反序列化它..
  • 没问题。您是否尝试过强烈键入您的返回对象,然后在您的测试中将 jsonResult.Data 作为该类型拆箱?另一方面,不确定为什么反射不起作用!
【解决方案2】:

您可以将您的 Json 反序列化为动态对象,然后请求您想要的属性

例子:

dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);

var propertyValue = obj.MyProperty; //Ask for the right property

您可以从 Nuget Json.Net 包中添加 Json 序列化程序。

【讨论】:

  • 我不能在 actionresult 上使用 newtonsoft,这是我的控制器返回的内容。我想我应该指定得更好。
  • 好的,我想我现在明白你的帖子了。您可能在 json 中有问题,jsonResult.Data 的内容是什么?您将获得执行 JsonConvert.SerializeObject(jsonResult.Data) 的 json 字符串
  • 查看我对原始帖子的评论,了解 json 的样子,感谢您的帮助!
  • 这似乎不是一个有效的 Json,我猜你在 controller.BatchHistories 方法中可能有问题。
猜你喜欢
  • 2014-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-01
  • 2011-05-03
  • 2016-08-14
  • 1970-01-01
  • 2017-06-07
相关资源
最近更新 更多