单元测试静态类的静态方法

时间:2018-03-16 10:10:10

标签: c# unit-testing

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()
{

}

5 个答案:

答案 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"));
    }