如何在mvc中对未格式化的方法进行单元测试?

时间:2014-01-06 14:40:42

标签: unit-testing asp.net-mvc-4

我必须对ASP.NET MVC 4.0中一个非常大且未格式化的方法进行单元测试。

以下是行动守则方法: -

    public ActionResult GetDetails(string ProdName, int ProdArea, int ProdAreaId= 0)
    {
        if (ProdAreaId == 0 && ProdArea == 1 && System.Web.HttpContext.Current.Session["ResponseProdAreaId"] != null)
        {
            ProdAreaId = (int)System.Web.HttpContext.Current.Session["ResponseProdAreaId"];
        }
        if (string.IsNullOrEmpty(ProdName))
        {
            if (System.Web.HttpContext.Current.Session["ProdName"] == null)
            {
                ProdName = Guid.NewGuid().ToString();
                System.Web.HttpContext.Current.Session["ProdName"] = ProdName;
            }
            else
            {
                ProdName = System.Web.HttpContext.Current.Session["ProdName"].ToString();
            }
        }
        else
        {
            ProdName = ProdName.Replace("___", " ");
        }


        List<StateDetail> stateList = ProductService.GetAllStates().Where(n => n.FKCountryID == (int)Countries.UnitedStates).ToList();

        ProductAddressViewModel model = new ProductAddressViewModel
        {
            ProdArea = ProdArea,
            FKProductID = CurrentProductId
        };

        model.States = stateList != null ? new SelectList(stateList, "StateID", "StateCode") : null;

        if (System.Web.HttpContext.Current.Session[“ProdAddresses”] != null && ProdAreaId == 0 && ProdArea == 1)
        {
            List<ProductAddressDto> lstprodaddresses = (List<ProductAddressDto>)System.Web.HttpContext.Current.Session[“ProdAddresses”];
            if (lstprodaddresses.Count > 0)
            {
                AddressDto addrDto = lstprodaddresses.First().Address;
                //save address in DB
                model.Address1 = addrDto.Address1;
                model.Address2 = addrDto.Address2;
                model.ProdArea = 1;
                model.City = addrDto.City;
                model.IsDefault = true;
                model.ProdName = model.ProdName;
                model.SelectedAddressTypeID = (int)AddressType.Street;
                model.ZIPCode = addrDto.ZIPCode;
                model.SelectedStateId = addrDto.FKStateID;
                model.AddressTypes = GetAddressTypes();
            }
        }
        else if (model.FKProductID > 0)
        {
            ToolDto tool = ToolService.GetToolDetails(model.FKProductID);

            if (ProdAreaId > 0)
            {
                model.AddressTypes = GetAddressTypes();
                ProductAddressDto prodaddr = tool.ToolAddresses.First(n => n.Tool_AddressID == ProdAreaId);
                model.Address1 = prodaddr.Address.Address1;
                model.Address2 = prodaddr.Address.Address2;
                model.City = prodaddr.Address.City;
                model.SelectedStateId = prodaddr.Address.FKStateID;
                model.ZIPCode = prodaddr.Address.ZIPCode;
                model.SelectedAddressTypeID = prodaddr.Address.FKAddressTypeID;
                model.IsDefault = prodaddr.IsDefault;
                model.FKAddressID = prodaddr.FKAddressID;
                model.Tool_AddressID = prodaddr.Tool_AddressID;
                model.FKProductID = prodaddr.FKProductID;
                model.AddressTypes = GetAddressTypes();
            }
            else
            {
                //address types
                List<int> excludeAddrTypes = new List<int>();
                foreach (ProductAddressDto prodadrdto in tool.ToolAddresses)
                {
                    if (prodadrdto.Tool_AddressID != ProdAreaId)
                    {
                        excludeAddrTypes.Add(prodadrdto.Address.FKAddressTypeID);
                    }
                }
                if (System.Web.HttpContext.Current.Session[“ProdAddresses”] != null)
                {
                    excludeAddrTypes.Add((int)AddressType.Street);
                }

                var addrtypes = from AddressType e in Enum.GetValues(typeof(AddressType))
                                where !excludeAddrTypes.Contains((int)e)
                                select new { Id = (int)e, Name = e.ToString() };

                model.AddressTypes = addrtypes.Select(x => new SelectListItem
                {
                    Value = x.Id.ToString(),
                    Text = x.Name
                });
                if (tool.ToolAddresses.Count == 0)
                {
                    model.IsDefault = (ProdArea == 1);
                }
            }
        }
        else
        {
            //filter out address types if responsed tool is there
            if (System.Web.HttpContext.Current.Session[“ProdAddresses”] != null)
            {
                List<int> excludeAddrTypes = new List<int>();
                excludeAddrTypes.Add((int)AddressType.Street);
                var addrtypes = from AddressType e in Enum.GetValues(typeof(AddressType))
                                where !excludeAddrTypes.Contains((int)e)
                                select new { Id = (int)e, Name = e.ToString() };
                model.AddressTypes = addrtypes.Select(x => new SelectListItem
                {
                    Value = x.Id.ToString(),
                    Text = x.Name
                });
            }
            else
            {
                model.AddressTypes = GetAddressTypes();
            }
            model.IsDefault = (ProdArea == 1);
        }
        model.ProdName = ProdName;
        return PartialView("_AddUpdateAddress", model);
    }
  
    

可能方法格式不正确。但我必须进行单元测试。我已经用不同的方式做了。但我不确定它的正确性。     我想知道我们应该如何对这样一个大而无格式的方法进行单元测试。

  

任何人都可以帮我解决这个问题吗?

以下是我的单元测试方法的代码: -

    [TestMethod]
    public void GetDetailsTest_NotEmpty()
    {                      
        var ProdName = random.ToString();
        var ProdArea = random.Next();
        var ProdAreaId = 0;

        var _toolServiceMock = new Mock<IToolService>();
        var _lookupServiceMock = new Mock<ILookupService>();

        var stateList = new List<StateDto> { 
            new StateDto() { StateID = random.Next(), StateCode = Guid.NewGuid().ToString(), Description = random.ToString(), FKCountryID = 1 },
            new StateDto() { StateID = random.Next(), StateCode = Guid.NewGuid().ToString(), Description = random.ToString(), FKCountryID = random.Next() },
        };

            _lookupServiceMock.Setup(s => s.GetAllStates()).Returns(stateList); // .Returns(stateList);

        //Arrange
        CustomerDto cust = _toolService.LookupCustomers("", "").FirstOrDefault();
        if (cust != null)
        {
            ToolDto tool = _toolService.GetToolDetails(cust.Tool.toolId);
            if (tool.ToolAddresses.Count > 0 && tool.ToolAddresses.First().Address != null)
            {
                HttpContext.Current.Session["FKToolID"] = cust.FKToolID;

                var controller = new ToolController(_toolServiceMock.Object);

                PartialViewResult result = controller.SelectAddress(cust.Tool.Name, 1, tool.ToolAddresses.First().Tool_AddressID) as PartialViewResult;
                var viewmodel = (ToolAddressViewModel)((ViewResultBase)(result)).Model;
                if (viewmodel != null)
                {
                    //Act                    
                    Assert.AreEqual(tool.ToolAddresses.First().Address.Address1, viewmodel.Address1);
                    Assert.AreEqual("_AddUpdateAddress", result.ViewName);
                    Assert.IsInstanceOfType(viewmodel, typeof(ToolAddressViewModel));
                }

                //Act
                _lookupServiceMock.VerifyAll();
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

首先,你的方法太复杂太长了。 使您的行动简短,并且有责任遵守SOLID原则(http://en.wikipedia.org/wiki/SOLID_(object-oriented_design))。 它将使您的方法更容易测试。

为了帮助您解决问题,您可以使用代码快速执行操作:

  • 在内部虚拟方法中拆分您的操作,每个方法都有一个问题(内部在单元测试项目中可测试,虚拟可以模拟它们)。
  • 将[assembly:InternalsVisibleTo(“YourTestAssembly”)]放在您的控制器上
  • 在您的单元测试项目中,您将能够单独测试任何内部方法。
  • 最后,要测试您的操作,请使用模拟框架(RhinoMock,Moq)来模拟所有内部虚拟方法并测试操作的逻辑(模拟框架生成的代理将让您模拟虚拟方法)。

这是在不破坏现有应用程序的情况下测试逻辑的最简单方法。 不方便的是,你的逻辑是内部方法,让整个组件都能够使用它。