【问题标题】:Why I'm getting NullReferenceException while trying to refer to Moq Object in unit testing?为什么在单元测试中尝试引用 Moq 对象时出现 NullReferenceException?
【发布时间】:2018-09-20 09:46:22
【问题描述】:

我有两个班级:

  • ProductController 类与 SingleProduct 动作
  • Helper 类有自己的方法 getProduct(ProductsContext db, string id) 从数据库中检索指定的产品

我正在尝试使用 Moq 框架为 SingleProduct 操作创建单元测试。 我正在为Helper 对象创建模拟,但是当测试运行时,我收到NullReferenceException 模拟Helper 对象。

我做错了什么?

[TestMethod]
public void ProductNotFoundTest()
{
    var mockHelper = new Mock<Helper>();
    mockHelper.Setup(h => h.getProduct(It.IsAny<ProductsContext>(), It.IsAny<string>())).Returns(It.IsAny<Product>());

    ProductController controller = new ProductController(mockHelper.Object);

    ViewResult result = controller.SingleProduct("i'm not exist") as ViewResult;
    Assert.AreEqual("~/Views/Product/ProductNotFound.cshtml", result.ViewName);
}

namespace OnlineStoreParser.Controllers
{
    public class ProductController : Controller
    {
        private Helper _h;        

        public ProductController(Helper h)
        {
            Helper _h = h;
        }

        public ProductController()
        {
            _h = new Helper();
        }

        public ActionResult SingleProduct(string id)
        {            
            Product product;

            using (var context = new ProductsContext())
            {
                // Find product with specified ID
                product = _h.getProduct(context, id);

                if(product != null)
                {
                    ViewBag.History = product.History;
                    ViewBag.Images = product.Photos;
                    return View(product);
                }                
                else
                {
                    return View("~/Views/Product/ProductNotFound.cshtml");
                }
            }
       }
   }   
}  

namespace OnlineStoreParser.Models
{
    public class Helper
    {
        public Helper() { }

        public virtual Product getProduct(ProductsContext db, string id)
        {
            return db.Products.SingleOrDefault(p => p.ProductId == id);
        }
    }
}  

【问题讨论】:

  • 在产品控制器中,我看到 ProductsContext 没有模拟对象,这可能是原因吗?
  • 据我了解,我在 ProductController 构造函数中创建此对象并将其分配给 ProductController 的字段 - _h 。然后在 SingleProduct 操作中,我调用该对象的 getProduct() 方法。如果我错了,请纠正我
  • 只需按照与Helper 相同的方式进行操作即可:) 您必须像使用第一个构造函数一样通过构造函数设置所有要模拟的类。跨度>
  • 很好,我不是在谈论辅助对象。我说的是您在控制器的 SingleProduct 方法中传递给 _helper 对象的 ProductsContext 对象。那是空的。
  • 同意@MightyBadaboom 你需要在控制器中模拟 ProductsContext 对象

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


【解决方案1】:

把你的构造函数改成这个。

private Helper _h;    
private ProductsContext _productsContext;

public ProductController(Helper h, ProductsContext productsContext)
{
    _h = h;
    _productsContext = productsContext;
}

你有两个错误。

using (var context = new ProductsContext())

您正在代码中创建一个新的ProductsContext;即使在您的测试中也是不好的做法,因为您也不想测试依赖项。

在你的构造函数中你正在做

public ProductController(Helper h)
{
    Helper _h = h;
}

这不是你想做的。您想设置变量 _h = h; 而不是创建新变量(这在构造函数之外不可用,这意味着在您的方法 SingleProduct 中您的变量 _h 未按预期设置。

最后但同样重要的是,您不应在模拟中返回 It.IsAny&lt;Product&gt;()。返回一个新实例。或者你的测试只是null

另一个提示:您仅在您的Helper 中使用ProductsContext。明智的做法是从ProductController 中删除它并将其添加到构造函数中的ProductsContext,就像我建议在ProductsController 中使用Helper 一样,因为您的ProductsController 现在不需要ProductsContext完全没有。

【讨论】:

  • 哇!非常感谢。你的建议是无价的:)
  • 我还有一个关于使用的问题 (var context = new ProductsContext()) {} 据我了解,我不再需要使用这种结构,而且创建新 ProductsContext 一次就足够简单了将其用于所有操作。我说的对吗?
  • 欢迎您。是的,您可以创建一次并将其用于所有操作。感谢您提前接受我的回答,祝您好运
  • 我对你的提示也有疑问。您的意思是将Helper 移动到ProductContext 类并在那里创建Helper 实例还是将ProductContext 移动到Helper?我对此有点困惑:)
  • 第二个。将上下文移动到帮助器,因为您的控制器不需要它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
  • 2012-09-23
  • 1970-01-01
  • 2018-03-25
  • 1970-01-01
  • 2014-05-02
  • 2020-08-02
相关资源
最近更新 更多