如何在 ASP.Net MVC 中对采用对象数组和 returns JsonResult 的 Action 方法进行单元测试

How to unit test an Action method that takes Array of an Object and returns JsonResult in ASP.Net MVC

我正在尝试在 Visual C# Unit Test 项目中编写单元测试。

我传递了一个空 ArrayFrame class 并且 returns 一个 JSON 对象。

    [HttpPost]
    public JsonResult SubmitBowlingScore(Frame[] frames)
    {
        int totalScore= 0;
        var objScore = new EngineService();

        for (int i = 0; i < frames.Length; i++)
        {
            Boolean wasSpare = false;

            if (i > 0 && objScore.IsSpare(frames[i-1]))
            {
                wasSpare = true;
            }
            totalScore += objScore.CalculateScore(frames[i], wasSpare);
        }

        return Json("{\"score\":"+ totalScore + "}");
    }

希望通过以下条目进行测试:但不知道怎么做!!!

 [{""1stRoll"":2,""2ndRoll"":2 ,""3rdRoll"":0},
  {""1stRoll"":4,""2ndRoll"":8 ,""3rdRoll"":0},
  {""1stRoll"":6,""2ndRoll"":2 ,""3rdRoll"":0}];

任何 help/idea/suggestion 将感谢以下单元测试。 SubmitBowlingScore() 如何将 Frame [] 数据作为参数?

    [TestMethod]
    public void SubmitBowlingScore()
    {
        //Arrange
        HomeController controller = new HomeController();
        //Act
        JsonResult result = controller.SubmitBowlingScore(**What goes here???**) as JsonResult;

        //Assert
        Assert.IsNotNull(JsonResult, "No JsonResult returned from action method.");
        Assert.AreEqual(@"{[{""1stRoll"":""2"",""2ndRoll"":2 ,""3rdRoll"":0},{""1stRoll"":""2"",""2ndRoll"":8 ,""3rdRoll"":0},{""1stRoll"":""6"",""2ndRoll"":2 ,""3rdRoll"":0}],""Count"":3,""Success"":true}",
               result.Data.ToString());
    }

您正在将业务逻辑与表示逻辑混合在一起。您应该将控制器方法的整个主体移动到一个根据帧计算分数的对象。一旦你掌握了它,就没有什么可以在控制器中测试了(除非你不信任 MVC 框架..)

我对你的 Frame 模型的演绎:

public class Frame
{
    public int FirstRoll { get; set; }
    public int SecondRoll { get; set; }
    public int ThirdRoll { get; set; }
}

这里是作为扩展的业务逻辑。你可能想把它分解成它自己的 class 或者可能让它成为你的 EngineService class.

的成员
public static class FrameExtensions
{
    public static int SumFrameScores(this Frame[] frames)
    {
        //break out early if no frames have been recorded
        if (frames.Length == 0) return 0;

        int totalScore = 0;
        var objScore = new EngineService();

        for (int i = 0; i < frames.Length; i++)
        {
            bool wasSpare = objScore.IsSpare(frames[i - 1]);
            totalScore += objScore.CalculateScore(frames[i], wasSpare);
        }

        return totalScore;
    }
}

测试时,您可以直接针对 C# classes/类型进行测试,因此您无需担心 JSON/presentation 层数据转换。

[TestMethod]
public void SubmitBowlingScore()
{
    //Arrange
    var frames = new Frame[]
    {
            new Frame {FirstRoll = 2, SecondRoll = 2, ThirdRoll = 0},
            new Frame {FirstRoll = 2, SecondRoll = 6, ThirdRoll = 0},
            new Frame {FirstRoll = 0, SecondRoll = 9, ThirdRoll = 0}
    };
    //Act
    var score = frames.SumFrameScores();

    //Assert
    Assert.AreEqual(21, score);
}

最后,您的控制器将减少为以下内容:

[HttpPost]
public JsonResult SubmitBowlingScore(Frame[] frames)
{
    var finalScore = frames.SumFrameScores();
    return Json(new { score = finalScore });
}