2011-02-14 5 views
39

:JsonResult를 반환하는 Action 메서드를 단위 테스트하는 방법? 나는이 같은 컨트롤러가있는 경우

[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"라는 속성이 있으므로 문제가 무엇인지 확실하지 않습니다.

+0

다시 편집 - var items = (IEnumerable) actionResult.Data와 같은 것을 시도해 볼 수 있습니다. foreach (동적 obj 항목) {...} –

+1

여기에서 ' '으로 테스트했습니다. var list = (IList) data; Assert.AreEqual (list.Count, 2); 동적 obj = 데이터 [0]; Assert.AreEqual (obj.id, 12); Assert.AreEqual (obj.name, "Fred"); Assert.AreEqual (obj.type, 'a'); obj = 데이터 [1]; Assert.AreEqual (obj.id, 14); Assert.AreEqual (obj.name, "Jim"); Assert.AreEqual (obj.type, 'c'); foreach (목록에 동적 d) { if (d.id == null) throw new InvalidOperationException(); }'괜찮 았던 것처럼 보였습니다 ... –

+0

내일 내가 사무실에 도착했을 때 그 코드를 사용해 보도록하겠습니다. 건배. – RPM1984

답변

14

RPM, 올바른 것으로 보입니다. 나는 아직도 dynamic에 대해 배울 것이 많고 Marc의 접근 방식을 사용할 수 없습니다. 그래서 여기에 제가 어떻게 그것을하고 있었는지가 있습니다. 도움이 될 것입니다.

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

다행 나는 Marc의 솔루션을 작동 시키려고 혼자만 있지는 않습니다. 이것은 잘 작동합니다. 내 대답을 삭제하고 확실히 받아들이는 편이 낫다. 감사! – RPM1984

+1

레코드의 경우 동적 솔루션이 효과적입니다. 기본적으로 더 예쁜 구문을 사용하는 것과 같습니다. 내부적으로 여전히 리플렉션을 사용하고있을 것입니다. ViewBag는 구문이 더 예쁜 ViewData와 비슷합니다. 나는 아직 그것을 구현할만큼 역동적 인 것으로 보지 않았다. 나는 약간의 가동 중지 시간이있을 때 나는 할 것이다. 나는 그것이 IDynamicObject를 구현하고 JsonResult.Data를 그것으로 포장하는 것을 알고있다. –

+1

ThrowIfNull 메서드의 출처는 어디입니까? 확장하고있는 수업이 있습니까, 아니면 무언가를 놓치고 있습니까? – morganpdx

49

내가이 사람에 조금 늦게 해요 알고,하지만 내가 발견

JsonResult은 익명 객체를 반환하며 기본값은 internal이므로 테스트 프로젝트에서 볼 수 있도록해야합니다.

ASP.NET MVC 응용 프로그램 프로젝트를 열고 Properties 폴더에서 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

가 나는 기록이 하나가 좋을 거라 생각 했어요. - 예상되는 데이터가 결과 세트 : 난 그냥이 같은 유닛 테스트 실행

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

그리고 :

1

내가 매트 그리어에서 솔루션을 확장하고이 작은 확장을 마련 매력처럼 작동

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

- 결과를 어설 :

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

여기에 하나 I 유 아마도 누군가에게 유용 할 것입니다. 클라이언트 측 기능에 사용하기 위해 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); 
} 
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); 
     } 
    } 
} 
5

내가 조금 늦게 파티에 있어요,하지만 나는 나 다음 dynamic 속성을 사용할 수 있습니다 약간의 래퍼를 만들었습니다. 이 답변으로 ASP.NET 코어 1.0 RC2에서이 작업을 수행 할 수 있지만 resultObject.Data으로 resultObject.Value을 바꾸면 비 핵심 버전에서도 작동합니다.

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

시험에 정확히 JSON 데이터 결과가 당신에게 다음해야 무엇을 알고있는 경우 다음과 같이 할 수 있습니다.

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

P. FluentAssertions.Mvc5를 사용했다면 이렇게 될 것입니다.하지만 사용하는 테스트 도구로 변환하는 것은 어렵지 않습니다.

관련 문제