我正在尝试为现有的MVC Web应用程序编写单元测试。因为我面临着一些问题,如用户身份和服务呼叫。
我的基本控制器:
public class BaseController : Controller
{
public AppUser CurrentUser
{
get
{
return new AppUser(this.User as ClaimsPrincipal);
}
}
}
控制器
public class NewsController : BaseController
{
private readonly iNewsService _newsService;
private readonly IMapper _mapper;
public NewsController(iNewsService newsService, IMapper mapper)
{
_newsService = newsService;
_mapper = mapper;
}
public ActionResult List(int CompanyID == 0)
{
var data = _newsService.List(CompanyID, CurrentUser.CompanyType);
return View();
}
}
测试代码:
[TestClass]
public class NewsControllerTest
{
[TestMethod]
public void NewsList()
{
var mockNewsService = new Mock<iNewsService>();
var mockMapper = new Mock<IMapper>();
IList<Claim> claimCollection = new List<Claim>
{
new Claim("UserName", "admin"),
new Claim("CompanyType", "true"),
};
var identityMock = new Mock<ClaimsIdentity>();
identityMock.Setup(x => x.Claims).Returns(claimCollection);
var cp = new Mock<ClaimsPrincipal>();
cp.Setup(m => m.HasClaim(It.IsAny<string>(), It.IsAny<string>())).Returns(true);
cp.Setup(m => m.Identity).Returns(identityMock.Object);
var contextMock = new Mock<HttpContextBase>();
contextMock.Setup(ctx => ctx.User).Returns(cp.Object);
var controllerContextMock = new Mock<ControllerContext>();
controllerContextMock.Setup(con => con.HttpContext).Returns(contextMock.Object);
controllerContextMock.Setup(con => con.HttpContext.User).Returns(cp.Object);
NewsController controller = new NewsController(mockNewsService.Object, mockMapper.Object);
controller.ControllerContext = controllerContextMock.Object;
// Act
ViewResult result = controller.List(1) as ViewResult;
// Assert
Assert.IsNotNull(result);
}
}
AppUser Class:
public class AppUser : ClaimsPrincipal
{
public AppUser(ClaimsPrincipal principal) : base(principal)
{
}
public string Name
{
get
{
return this.FindFirst("UserName").Value;
}
}
public string CompanyType
{
get
{
return this.FindFirst("CompanyType").Value;
}
}
}
INewsServices:
public interface iNewsService
{
IEnumerable<Model.News> List(string companyType, string CompanyID);
}
注意:INewsServices是单独的库
这是我的实际代码,但它不起作用总是我的CurrentUser
是空值。我无法在父控制器的CurrentUser
中分配值,有时我的新闻服务也没有调用List方法。
答案 0 :(得分:2)
如何模仿ClaimsPrincipal
导致FindFirst
返回null
,当您致电Value
时,它会获得NRE。无需模拟声明主体只需为测试创建新实例。
[TestClass]
public class NewsControllerTest {
[TestMethod]
public void _NewsList() {
//Arrange
var companyId = 1;
var companyType = "someType";
var claims = new List<Claim>
{
new Claim("UserName", "admin"),
new Claim("CompanyType", companyType),
};
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims));
var contextMock = new Mock<HttpContextBase>();
contextMock.Setup(_ => _.User).Returns(principal);
var fakeNews = new List<News>() { new News(), new News() };
var mockNewsService = new Mock<INewsService>();
mockNewsService
.Setup(_ => _.List(It.IsAny<string>(), It.IsAny<string>())
.Returns(fakeNews);
var controller = new NewsController(mockNewsService.Object, Mock.Of<IMapper>());
controller.ControllerContext = new ControllerContext(contextMock.Object, new RouteData(), controller);
// Act
ViewResult result = controller.List(companyId) as ViewResult;
// Assert
Assert.IsNotNull(result);
mockNewsService.Verify(_ => _.List(It.IsAny<string>(), It.IsAny<string>()), Times.AtLeastOnce);
}
}
您还应考虑更新AppUser
以避免NRE
public class AppUser : ClaimsPrincipal {
public AppUser(ClaimsPrincipal principal)
: base(principal) {
}
public string Name {
get {
return this.FindFirst("UserName")?.Value;
}
}
public string CompanyType {
get {
return this.FindFirst("CompanyType")?.Value;
}
}
}