执行测试用例Put_IsUnlockUser_ReturnsTrue时BaseController抛出空引用异常
解决测试用例Put_IsUnlockUser_ReturnsTrue中的空引用异常
问题场景
执行测试用例Put_IsUnlockUser_ReturnsTrue时触发空引用异常,相关代码如下:
public class AccountController : BaseController { public ResponseTransferObject Put(AccountPutRequest request) { if (!string.IsNullOrEmpty(request.UnlockUser)) { if (!Session.RoleName.Equals("Administrator", StringComparison.InvariantCultureIgnoreCase)) { return object; // 此处为语法错误,应返回ResponseTransferObject实例 } } // 缺少其他分支的返回逻辑 } } public void Put_IsUnlockUser_ReturnsTrue() { AccountController accountController = new AccountController(); ResponseTransferObject responseTransferObject = new ResponseTransferObject(); try { responseTransferObject = accountController.Put(new AccountPutRequest { UnlockUser = "Wind" }); Assert.IsNotEmpty(responseTransferObject.ToString()); } catch { Assert.IsTrue(false); } } public class BaseController : ApiController { public SessionUser Session { get; set; } public BaseController() { Session = HttpContext.Current.Session["MyUser"] as SessionUser; } }
异常原因
测试环境中不存在真实的HttpContext.Current.Session,因此BaseController构造函数从HttpContext.Current.Session["MyUser"]获取SessionUser时返回null,导致Session属性为空。当AccountController的Put方法访问Session.RoleName时,触发空引用异常。
解决方案
方案1:测试中手动设置Session属性
直接为控制器的Session属性赋值模拟的SessionUser对象,快速解决空引用问题:
public void Put_IsUnlockUser_ReturnsTrue() { AccountController accountController = new AccountController(); // 手动注入模拟的SessionUser,避免空引用 accountController.Session = new SessionUser { RoleName = "Administrator" }; ResponseTransferObject responseTransferObject; try { responseTransferObject = accountController.Put(new AccountPutRequest { UnlockUser = "Wind" }); Assert.IsNotEmpty(responseTransferObject.ToString()); } catch { Assert.IsTrue(false); } }
方案2:重构代码,用依赖注入解耦Session
通过构造函数注入SessionUser,消除对HttpContext的直接依赖,让测试更灵活:
修改BaseController和AccountController
public class BaseController : ApiController { public SessionUser Session { get; set; } // 构造函数注入SessionUser public BaseController(SessionUser sessionUser) { Session = sessionUser; } } public class AccountController : BaseController { public AccountController(SessionUser sessionUser) : base(sessionUser) { } public ResponseTransferObject Put(AccountPutRequest request) { if (!string.IsNullOrEmpty(request.UnlockUser)) { if (!Session.RoleName.Equals("Administrator", StringComparison.InvariantCultureIgnoreCase)) { return new ResponseTransferObject { /* 设置对应属性 */ }; } return new ResponseTransferObject { /* 设置正常逻辑的属性 */ }; } return new ResponseTransferObject { /* 设置UnlockUser为空时的属性 */ }; } }
测试用例中注入模拟对象
public void Put_IsUnlockUser_ReturnsTrue() { // 创建模拟的SessionUser var mockSession = new SessionUser { RoleName = "Administrator" }; AccountController accountController = new AccountController(mockSession); ResponseTransferObject responseTransferObject; try { responseTransferObject = accountController.Put(new AccountPutRequest { UnlockUser = "Wind" }); Assert.IsNotEmpty(responseTransferObject.ToString()); } catch { Assert.IsTrue(false); } }
方案3:用Moq模拟HttpContext(不修改现有代码结构)
如果不想改动原有代码,可以用Moq框架模拟HttpContext和Session:
using Moq; using System.Web; public void Put_IsUnlockUser_ReturnsTrue() { // 模拟Session并设置MyUser值 var mockSession = new Mock<HttpSessionStateBase>(); mockSession.Setup(s => s["MyUser"]).Returns(new SessionUser { RoleName = "Administrator" }); // 模拟HttpContext并关联Session var mockContext = new Mock<HttpContextBase>(); mockContext.Setup(c => c.Session).Returns(mockSession.Object); // 设置当前HttpContext HttpContext.Current = mockContext.Object; AccountController accountController = new AccountController(); ResponseTransferObject responseTransferObject; try { responseTransferObject = accountController.Put(new AccountPutRequest { UnlockUser = "Wind" }); Assert.IsNotEmpty(responseTransferObject.ToString()); } catch { Assert.IsTrue(false); } finally { // 清理HttpContext,避免影响其他测试 HttpContext.Current = null; } }
额外提示
原AccountController.Put方法中存在语法错误:return object应替换为具体的ResponseTransferObject实例,同时要补充所有代码分支的返回逻辑,避免编译错误或运行时异常。
内容的提问来源于stack exchange,提问作者Akash Sharma
相关产品推荐
相关产品推荐

