模拟控制器操作,将Request.InputStream设置为字符串

时间:2013-06-12 17:00:47

标签: c# asp.net-mvc-3 unit-testing mocking moq

我正在尝试测试从Request.InputStream读取JSON并输出动态的控制器操作。我不明白Mock Request.InputStream类型应该是什么。我已经尝试过它作为一个MemoryStream并传递给它一个字节数组,但它无法读取它。

到目前为止,我的模拟看起来像这样:

var str = "{ MediaItem: null, ParentId: 2897, Post: null, PostContent: hello }";
byte[] bytes = new byte[str.Length * sizeof(char)];
Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
var stream = new MemoryStream(bytes);

var request = new Mock<HttpRequestBase>();
request.SetupGet(x => x.InputStream).Returns(stream);
request.Setup(x => x.InputStream).Returns(stream);
request.Setup(x => x.Url).Returns(new Uri("http://localhost:35199/api/comment/create"));

var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);

CommentController controller = new CommentController(pr, ur, er, apr, ar);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);

ActionResult expected = null;
ActionResult actual = controller.Create();

JSON阅读器执行此操作:

public static dynamic SqueezeJson(HttpRequestBase Request)
{        
    var bodyText = "";
    using (var stream = Request.InputStream)
    {
        stream.Seek(0, SeekOrigin.Begin);
        using (var reader = new StreamReader(stream))
            bodyText = reader.ReadToEnd();
    }
    if (string.IsNullOrEmpty(bodyText)) return null;

    return JsonConvert.DeserializeObject<ExpandoObject>(bodyText, new ExpandoObjectConverter());
}

这会抛出此错误:

  

解析属性名称后的字符无效。期待':'但得到了:a。路径'',第1行,第6位。

编辑:我应该提到我没有重构控制器代码的自由。

2 个答案:

答案 0 :(得分:0)

看起来你的控制器做了太多工作。尝试在另一个类中抽象json reader,并将其注入控制器中。这样你将有2个独立的测试 - 一个用于读者本身,另一个用于控制器,它只是调用读者,而不是实际上不得不考虑读者如何工作。

像这样(伪代码):

public interface IJsonReader
{
   dynamic SqueezeJson(Stream stream);
}

public class JsonReader : IJsonReader
{
   //implement SqeezeJson method
}

public class MyController
{
   private readonly IJsonReader _jsonReader;
   public MyController(IJsonReader jsonReader)
   {
      _jsonReader = jsonReader;
   }

   public ActionResult Create()
   {
       var data = _jsonReader.SqeezeJson(Context.Request.InputStream);
       //... do wahtever needed
   }
}

// ... and the tests

[Test]
public void SqueezeJsonTest()
{
   //test that the reader works as expected
}

public void ControllerTest()
{
   //arrange
   var requestStream = Mock.Of<Stream>();
   var request = Mock.Of<HttpRequestBase>( r => 
       r.InputStream == requestStream &&
       r.Url == "http://whatever");
   var context = Mock.Of<HttpRequestBase>(c=>c.Request == request);

   dynamic sqeezedData = new ExpandoObject(); // populate with the expected data from reader
   var mockReader = new Mock<IJsonReader>();
   mockReader.Setup(r=>r.SqeezeJson(requestStream)).Returns(sqeezedData); 

   var controller = new MyController();
   controller.Context = context;

   //act
   var result = controller.Create();

   //assert
   //whatever is needed to verify that the controller processed the sueezed data
}

答案 1 :(得分:0)

只是将您的Json字符串粘贴到解析器中,但它失败了。您是否尝试将其更改为有效的Json表示?

{ "MediaItem": "null", "ParentId": "2897", "Post": "null", "PostContent": "hello" }

针对您的方案进行了更新:

var str = "{ \"MediaItem\": \"null\",\"ParentId\": \"2897\", \"Post\": \"null\", \"PostContent\": \"hello\" }";

HTH