15
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;
        }
  }

Above is some code that is used to test if the currently logged in user is an Admin, I want to unit test this section by passing in a different username and test if the result is correct.

I have heard that dependency injection would be the best way to do this. But I have no idea how to dependency inject into a static class and a static method.

Can anyone help me fill out the TestMethod below in order to pass in a username and test the method? (Not using enterprise)

[TestMethod]
public void IsCurrentUserAManagerTestIsAdmin()
{

}
4
  • If you can pass in WindowsIdentity to your method, you won't need DI - IsUserAManager(WindowsIdentity identity) Commented Mar 16, 2018 at 10:13
  • Dependency injection won't help here, because the method doesn't call any DI container to instantiate a WindowsIdentity. You only call the static GetCurrent method. One way to test this is using shims or some other mocking framework. Commented Mar 16, 2018 at 10:13
  • can't you create two test cases? one for failure that you stub out the name you need? and one for success? Commented Mar 16, 2018 at 10:30
  • So with a mocking framework, do I just need to accept a variable in the 'IsUserAManager' class and call it with a mock parameter in my test method? Commented Mar 16, 2018 at 10:33

4 Answers 4

9

Refactor your class a little to take an identity as a parameter.

public static class ApplicationUtils
{
    public static bool IsUserAManager(IIdentity identity)
    {
        if (identity == null)
            throw new NullReferenceException("identity");


        return identity.Name == "AdminUser";
    }
}

And Your Test Class using 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);
}
Sign up to request clarification or add additional context in comments.

3 Comments

You can abstract it down to just IIdentity if .Name is all that is being accessed as WindowsIdentity is an implementation concern
This answer works! Thanks so much, I do have one follow up question. So I'm debugging the test method and going through the 'IsUserAManager' class but I make a reference to 'ConfirgurationManager.AppSettings['adgroup'];' and it returns null.
Fixed this issue by passing in the adgroup in the same way as the username has been passed in.
6

One should try to avoid coupling code to static classes as they are difficult to test.

That said, with your current code as is, it can be refactored to allow certain separations of concerns and a more fluent API via extension methods.

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;
    }
}

The following test is used as an example to demonstrate how the above is used.

Moq was used as mocking framework

[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);
}

That done I would now like to suggest you refactor your code to make it more SOLID.

Abstract the functionality of getting the current user out into a service provider.

public interface IIdentityProvider {
    IIdentity CurrentUser { get; }
}

Pretty simple with an even simpler implementation.

public class DefaultIdentityProvider : IIdentityProvider {
    public IIdentity CurrentUser {
        get { return WindowsIdentity.GetCurrent(); }
    }
}

If using DI you can now inject the provider into dependent classes that have need to access the current user.

This allows the code to more flexible and maintainable as mocks/stubs of the provider and user can be used for isolated unit tests. The extension methods remain the same as they have very simple concerns.

Here is a simple example of a test for the extension method from earlier.

[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);
}

Purely for demonstrative purposes, the test for the IsManager extension method only really needs an IIdentity to be exercised.

Assert.IsTrue(Mock.Of<IIdentity>(_ => _.Name == "AdminUser").IsManager());

2 Comments

This is a great answer with a lot of explanation which gives the OP an alternative implementation, I'm not sure why it would be down voted.
@DavidMartin who knows what motivates some members of this fine establishment.
2

When your code is difficult to test, changing the code is a viable option! In this case, consider having the IsCurrentUserAManager receive the username as an input parameter (and rename it to IsUserAManager to reflect the change in behavior). It would look something like this:

public static class ApplicationUtils
{
   public static bool IsUserAManager(string username)
   {
      bool inAdmin;

      if (username == "AdminUser") {
         inAdmin = true;
      } else {
         inAdmin = false;
      }

      return inAdmin;
   }
}

This will allow you to send in different values for testing different scenarios. If however the entire class as it is cannot appear in the UT (due to environment constraints on initialization, for example), consider having just the business logic exported to a seperate non static class and write your UT for that.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.