public static class ApplicationUtils
{
public static bool IsCurrentUserAManager()
{
var username = WindowsIdentity.GetCurrent().Name;
bool inAdmin;
if (username == "AdminUser") {
inAdmin = true;
} else {
inAdmin = false;
}
return inAdmin;
}
}
上面是一些用于测试当前登录用户是否为管理员的代码,我想通过传入不同的用户名对该部分进行单元测试,并测试结果是否正确。
我听说依赖注入是最好的方法。但我不知道如何依赖注入静态类和静态方法。
任何人都可以帮我填写下面的TestMethod,以传递用户名并测试方法吗? (不使用企业)
[TestMethod]
public void IsCurrentUserAManagerTestIsAdmin()
{
}
答案 0 :(得分:2)
稍微重构一下你的类,将身份作为参数。
public static class ApplicationUtils
{
public static bool IsUserAManager(IIdentity identity)
{
if (identity == null)
throw new NullReferenceException("identity");
return identity.Name == "AdminUser";
}
}
使用Moq
测试课程[TestMethod]
public void IsUserAManagerTestIsAdminReturnsFalse()
{
var mockedIdentity = new Moq.Mock<IIdentity>();
mockedIdentity.Setup(x => x.Name).Returns("notanadmin");
var result = ApplicationUtils.IsUserAManager(mockedIdentity.Object);
Assert.IsFalse(result);
}
[TestMethod]
public void IsUserAManagerTestIsAdminReturnsTrue()
{
var mockedIdentity = new Moq.Mock<IIdentity>();
mockedIdentity.Setup(x => x.Name).Returns("AdminUser");
var result = ApplicationUtils.IsUserAManager(mockedIdentity.Object);
Assert.IsTrue(result);
}
答案 1 :(得分:1)
当您的代码难以测试时,更改代码是一个可行的选择!
在这种情况下,请考虑让IsCurrentUserAManager
接收用户名作为输入参数(并将其重命名为IsUserAManager
以反映行为的变化)。它看起来像这样:
public static class ApplicationUtils
{
public static bool IsUserAManager(string username)
{
bool inAdmin;
if (username == "AdminUser") {
inAdmin = true;
} else {
inAdmin = false;
}
return inAdmin;
}
}
这将允许您发送不同的值以测试不同的方案。但是,如果整个类不能出现在UT中(例如,由于初始化的环境限制),请考虑将业务逻辑导出到单独的非静态类并为此编写UT。
答案 2 :(得分:1)
应该尽量避免将代码与静态类耦合,因为它们很难测试。
也就是说,使用您当前的代码,可以通过扩展方法对其进行重构以允许某些关注点分离和更流畅的API。
public static class ApplicationUtils {
public static Func<IIdentity> userFactory = () => WindowsIdentity.GetCurrent();
public static IIdentity CurrentUser { get { return userFactory(); } }
public static bool IsManager(this IIdentity identity) {
return identity != null && string.Compare(identity.Name, "AdminUser", true) == 0;
}
public static bool IsAuthenticated(this IIdentity identity) {
return identity != null && identity.IsAuthenticated;
}
}
以下测试用作演示如何使用上述测试的例子。
Moq被用作模拟框架
[TestMethod]
public void IsManager_Should_Return_True_For_AdminUser() {
//Arrange
var name = "AdminUser";
var identity = Mock.Of<IIdentity>(_ => _.Name == name);
ApplicationUtils.userFactory = () => identity;
//Act
var actual = ApplicationUtils.CurrentUser.IsManager();
//Assert
Assert.IsTrue(actual);
}
这样做我现在建议您重构代码以使其更加稳固。
摘要将当前用户带入服务提供商的功能。
public interface IIdentityProvider {
IIdentity CurrentUser { get; }
}
非常简单,实现更简单。
public class DefaultIdentityProvider : IIdentityProvider {
public IIdentity CurrentUser {
get { return WindowsIdentity.GetCurrent(); }
}
}
如果使用DI,您现在可以将提供者注入需要访问当前用户的依赖类。
这使得代码更加灵活和可维护,因为提供者和用户的模拟/存根可以用于隔离的单元测试。扩展方法保持不变,因为它们有非常简单的问题。
这是一个简单的扩展方法测试示例。
[TestMethod]
public void IsManager_Should_Return_True_For_AdminUser() {
//Arrange
var name = "AdminUser";
var identity = Mock.Of<IIdentity>(_ => _.Name == name);
var provider = Mock.Of<IIdentityProvider>(_ => _.CurrentUser == identity);
//Act
var actual = provider.CurrentUser.IsManager();
//Assert
Assert.IsTrue(actual);
}
纯粹出于演示目的,IsManager
扩展方法的测试只需要执行IIdentity
。
Assert.IsTrue(Mock.Of<IIdentity>(_ => _.Name == "AdminUser").IsManager());
答案 3 :(得分:0)
如果你觉得你在你的代码库中移动山脉而你真的很累,那么现在是时候为你考虑依赖注入了。 一点提示:不要在DI中使用静态类。他们真的很难维护,moq等等。
对于您的方案,请使用Microsoft.Fake。 因为你应该模仿来自WindowsIdentity.GetCurrent();
的回复答案 4 :(得分:0)
public static class ApplicationUtils
{
// this is not testable, because I dont use DI
public static bool IsCurrentUserAManager() => TestableMethod(WindowsIdentity.GetCurrent().Name);
// This is testable because it contains logics (if-else)
public static bool TestableMethod(string username) => username == "AdminUser";
}
[TestMethod]
public void IsCurrentUserAManagerTestIsAdmin()
{
Assert.IsTrue(ApplicationUtils.TestableMethod("AdminUser"));
Assert.IsFalse(ApplicationUtils.TestableMethod("adminuser"));
}