А?Где я могу разместить свой сервис, чтобы мой контроллер и сервис не могли быть протестированы? - PullRequest
0 голосов
/ 07 июля 2011

Правильно ли я считаю, что мне нужно создать свой контроллер, передав ему экземпляр моего контекста И мой сервис, чтобы сделать его тестируемым?

Например: 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;
        }

    }
}

Ответы [ 2 ]

2 голосов
/ 07 июля 2011

Правильно ли я считаю, что мне нужно создать свой контроллер, передав ему экземпляр моего контекста И мою службу, чтобы сделать его тестируемым?

Вид.Это только половина работы, которую вам нужно сделать.Вторая половина - ослабить связь между вашими слоями с помощью абстракций.Ваш сервисный уровень должен реализовать интерфейс, который вы бы внедрили в конструктор вашего контроллера, обеспечивающий контракт между этими двумя и явно указав, что контроллеру нужен сервисный уровень, подчиняющийся этому контракту:

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

Теперь в вашемпродолжайте модульное тестирование и макетируйте его , используя одну из множества фальшивых рамок ( Rhino Mocks , NSubstitute , Moq , NMock , ...).

1 голос
/ 07 июля 2011

Вы можете использовать инжектор сеттера вместо инжектора конструктора на контроллере.

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 () вашего модульного теста используйте setters, чтобы «внедрить» вашу базу данных mock / stub.

Кроме того, использование интерфейса, а не DR405DBContext, облегчит mocking.

...