我正在使用ASP.NET MVC 3,MVCContrib,NUnit和Rhino Mocks。我发布了这个,但无法得到答案。人们更关注我的编码,这有助于我得到一个合适的答案,让这个测试通过。
我正在尝试测试我的编辑视图。我不确定如何为视图编写测试代码。它是类型为NewsEditViewData的强类型视图。
当视图加载时,它会通过新闻服务中的ID获取新闻项目的数据。所以在我的测试中我创建了一个新闻服务的存根:
var id = 1;
var news = new News();
newsServiceStub
.Stub(x => x.FindById(id))
.Return(news);
现在我需要将此新闻项映射到NewsEditViewData。我有一个映射器(AutoMapper)为我做这个,在我的测试中我做了以下:
newsMapperStub
.Stub(x => x.Map(news, typeof(News), typeof(NewsEditViewData)))
.Return(newsEditViewData);
到目前为止,我不确定自己是否走上正轨?
然后我有以下代码:
// Act
var actual = sut.Edit(id);
不要使用我的代码,我想按照最佳实践做出回答。那么我需要在断言部分检查什么呢?我是否还需要检查是否已返回记录?我想的是:
actual
.AssertViewRendered()
.WithViewData<NewsEditViewData>()
.ShouldBe(newsEditViewData);
这失败了。有人可以帮我改写这个测试,以便它通过。我想要检查所有需要检查的内容。
这是完整的测试:
[Test]
public void Edit_should_render_Edit_view()
{
// Arrange
var id = 1;
var news = new News();
var newsEditViewData = new NewsEditViewData();
newsServiceStub
.Stub(x => x.FindById(id))
.Return(news);
newsMapperStub
.Stub(x => x.Map(news, typeof(News), typeof(NewsEditViewData)))
.Return(newsEditViewData);
// Act
var actual = sut.Edit(id);
// Assert
actual
.AssertViewRendered()
.WithViewData<NewsEditViewData>()
.ShouldBe(newsEditViewData);
}
更新2011-02-14:
在我的NewsController中,我有以下内容:
private INewsService newsService;
private IMapper newsMapper;
public NewsController(INewsService newsService)
{
Check.Argument.IsNotNull(newsService, "newsService");
this.newsService = newsService;
newsMapper = new NewsMapper(); // TODO: Use dependency injection
}
动作方法如下所示:
public ActionResult Edit(int id)
{
Check.Argument.IsNotZeroOrNegative(id, "id");
var news = newsService.FindById(id);
var newsEditViewData = (NewsEditViewData)newsMapper.Map(news, typeof(News), typeof(NewsEditViewData));
return View(newsEditViewData);
}
我在NUnit中遇到的错误是:
MyProject.Web.UnitTests.Controllers.NewsControllerTests.Edit_RenderView_EditView: MvcContrib.TestHelper.AssertionException:是MyProject.Web.Common.ViewData.NewsEditViewData但是期望MyProject.Web.Common.ViewData.NewsEditViewData
答案 0 :(得分:2)
您尚未显示任何控制器,存储库和模型。没有这些信息,这个问题几乎无法回答。所以让我们开始猜测。你有一个模型和一个视图模型:
public class News { }
public class NewsEditViewData { }
为了这篇文章的目的,我将离开他们没有任何属性。然后你可能有一个负责检索和保存模型的服务(视图模型永远不应该显示为服务层的in / out参数)。服务永远不应该知道视图模型:
public interface INewsService
{
News FindById(int id);
void CreateNews(News news);
}
然后你可能有一个映射器:
public interface IMapper
{
object Map(object source, Type sourceType, Type destinationType);
}
最后我想你有一个你想要测试的控制器:
public class NewsController : Controller
{
private readonly INewsService _newsService;
private readonly IMapper _newsMapper;
public NewsController(INewsService newsService, IMapper newsMapper)
{
_newsService = newsService;
_newsMapper = newsMapper;
}
public ActionResult Edit(int id)
{
// WARNING: Meaningless action ahead as it retrieves some
// model from the service and passes this model to
// the service back again for update. In the meantime
// the model is converted to a view model using a mapper
// and passed to the view. So totally meaningless in a real
// application but let's consider for the purpose of this demonstration
var news = _newsService.FindById(id);
_newsService.CreateNews(news);
var newsEditViewData = (NewsEditViewData)_newsMapper.Map(news, typeof(News), typeof(NewsEditViewData));
return View(newsEditViewData);
}
}
好的,直到这里,你应该提供这些信息。
现在我可以开始回答你关于单元测试的问题,这可能是这样的:
[Test]
public void Edit_should_fetch_news_model_from_service_given_an_id_parameter_create_news_and_pass_a_viewmodel_to_the_view()
{
// arrange
// TODO : move this part in the initialization section
// of your unit test to avoid repeating it on each method
var newsServiceStub = MockRepository.GenerateStub<INewsService>();
var newsMapperStub = MockRepository.GenerateStub<IMapper>();
var sut = new NewsController(newsServiceStub, newsMapperStub);
new TestControllerBuilder().InitializeController(sut);
var news = new News();
var id = 123;
var newsEditViewData = new NewsEditViewData();
newsServiceStub
.Stub(x => x.FindById(id))
.Return(news);
newsMapperStub
.Stub(x => x.Map(news, typeof(News), typeof(NewsEditViewData)))
.Return(newsEditViewData);
// act
var actual = sut.Edit(id);
// assert
actual
.AssertViewRendered()
.WithViewData<NewsEditViewData>()
.ShouldBe(newsEditViewData);
newsServiceStub.AssertWasCalled(x => x.CreateNews(news));
}