为什么在单元测试中尝试引用Moq对象时出现NullReferenceException?

时间:2018-09-20 09:46:22

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

我有两节课:

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

1 个答案:

答案 0 :(得分:2)

将构造函数更改为此。

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<Product>()。返回一个新实例。或仅为您的测试null

另一个提示:您仅在ProductsContext中使用Helper。最好将它从ProductController中删除,然后将其添加到构造函数中的ProductsContext中,就像我建议使用Helper中的ProductsController一样,因为您的{{1} }完全不需要ProductsController