0

我是否正确地认为我必须通过将我的上下文实例和我的服务传递给它来创建我的控制器以使其可测试?

例如: new Controller(mycontext,myservice)

我认为这是我需要更改代码的方式,但如果我不需要,我不想这样做。由于要使 MVC3 开箱即用,它要求控制器构造函数是无参数的,我认为这意味着我将不得不走 IoC 的道路。否则,即使在测试期间,我的向导操作中的代码也会保存到真实的 DBContext 中。

namespace mvc3test.Controllers
{

    public class WizardController : Controller
    {

        private DR405DBContext db;


        public WizardController(DR405DBContext dbContext)
        {
            db = dbContext;
        }

        public WizardController()
        {
            db = new DR405DBContext();
        }

        public ActionResult Index()
        {
            var model = new WizardViewModel();
            model.Initialize();
            return View(model);
        }

        [HttpPost]
        public ActionResult Index([Deserialize] WizardViewModel wizard)
        {


            //wizard.Steps[wizard.CurrentStepIndex] = step;
            if (ModelState.IsValid)
            {

                    //Always save.
                    var obj = new dr405();

                    //wire up to domain model;
                    foreach (var s in wizard.Steps)
                    {
                        Mapper.Map(s,obj,s.GetType(), typeof(dr405));
                    }

                    using (var service = new DR405Service())
                    {
                        //Do something with a service here.
                        service.Save(db, obj);
                    }


                if (!string.IsNullOrEmpty(Request.QueryString["next"]))
                {
                    wizard.CurrentStepIndex++;
                }
                else if (!string.IsNullOrEmpty(Request.QueryString["prev"]))
                {
                    wizard.CurrentStepIndex--;
                }
                else
                {
                    return View("Review", wizard);

                }
            }
            else if (!string.IsNullOrEmpty(Request.QueryString["prev"]))
            {
                wizard.CurrentStepIndex--;
            }

            return View(wizard);


        }

        public ActionResult Review(int id)
        {
            var service = new DR405Service();

            var dr405 = service.GetDR405ById(db, id);
            var wizard = new WizardViewModel();

            if (dr405 != null)
            {

                wizard.Initialize();

                foreach (var s in wizard.Steps)
                {
                    Mapper.Map(dr405, s, typeof(dr405), s.GetType());
                }
            }

            return View(wizard);
        }


        public ActionResult Transmit()
        {
            return View();

        }

        [HttpPost]
        public String Upload(HttpPostedFileBase FileData)
        {
            var saveLocation = Path.Combine(Server.MapPath("\\"), "returns\\" + DR405Profile.CurrentUser.TaxPayerID);
            System.IO.Directory.CreateDirectory(saveLocation);
            FileData.SaveAs(Path.Combine(saveLocation, FileData.FileName));
            ViewBag.Message = String.Format("File name: {0}, {1}Kb Uploaded Successfully.", FileData.FileName, (int)FileData.ContentLength / 1024);
            return ViewBag.Message;
        }

    }
}
4

2 回答 2

2

我是否正确地认为我必须通过将我的上下文实例和我的服务传递给它来创建我的控制器以使其可测试?

有点儿。这只是您需要做的工作的一半。后半部分是通过使用抽象来削弱层之间的耦合。您的服务层需要实现一个接口,您将将该接口注入到控制器的构造函数中,以强制执行这两者之间的合同,并明确说明控制器需要一个遵守此合同的服务层:

public WizardController(IMyService service) 
{
   this._service = service;
}

现在在您的单元测试中继续使用多个模拟框架之一(Rhino Mocks ,NSubstituteMoqNMock,...)来模拟它。

于 2011-07-07T18:36:58.460 回答
1

您可以在 Controller 上使用 setter 注入而不是构造函数注入。

public class WizardController : Controller
{
    public void setDBContext( DR405DBContext db) {
          this.db = db;
    }
}

或者

您可以使用服务定位器获取数据库并为其添加设置器。

public class DBServiceLocator
{
    private static DR405DBContext db = new DR405DBContext();

    public static DR405DBContext locate() {
          return db;
    }

    public static setContext(DR405DBContext db) {
          DBServiceLocator.db = db;
    }
}

在单元测试的 setup() 部分中,使用 setter 来“注入”模拟/存根数据库。

此外,使用接口而不是 DR405DBContext 将使模拟更容易。

于 2011-07-07T18:34:05.947 回答