Charan Tej
Charan Tej

Reputation: 61

How do I write a unit test when the system under test utilizes external static dependencies?

I am creating unit test for my method

[Authorize]
[HttpPost]
public async Task<JsonResult> UpdateDisplayName(string displayname)
{
    bool status = _myProfileService.UpdateDisplayName(displayname, SessionAdapter.Instance._userDetailsViewModel.id);

    if (status)
        SessionAdapter.Instance._userDetailsViewModel.display_name = displayname;

    return Json(new { status = status, displayname = displayname }, JsonRequestBehavior.AllowGet);
}

and my test method is

[TestMethod]
public async Task UpdateDisplayName_Test()
{
    //Arrange
    var controller = new HomeController(userServiceMock.Object, myProfileServiceMock.Object);

    string displayName = "display";
    const string expected = "{ status = False, displayname = display }";
    myProfileServiceMock.Setup(m => m.UpdateDisplayName(It.IsAny<string>(), 1)).Returns(false);

    //var controllerContextMock = new Mock<ControllerContext>();

    //Act
    var result = await controller.UpdateDisplayName(displayName) as JsonResult;

    //Assert
    Assert.AreEqual(expected, result.Data.ToString());
}

My Session Info Class is below, this class i am using in session adapter

  public  class SessionInfo
    {
        public string Id { set; get; }
        public string Email { set; get; }
        public string UserName { set; get; }
        public UserDetailsViewModel _userDetailsViewModel { set; get; }
        public string permission { set; get; }

        //public string organization { set; get; }
        public OrganizationViewModels Organization { set; get; }
        public List<UserTeamModels> teams { set; get; }
        public string status { set; get; }
        public string role { set; get; }
        public List<string> roles { set; get; }
    }

I am unable to instantiate SessionAdapter. How can I unit test this?

My Interface and sessionadapter class were looks like below

public interface ISessionAdapterService
    {
        void Clear();
        void Abandon();
        bool DoesSessionExists { get; }
        SessionInfo Instance { get; set; } 
    }


    public class SessionAdapterService : ISessionAdapterService
    {
        private string sessionKey = "sessionInfoKey";

        public bool DoesSessionExists
        {
            get
            {
                return HttpContext.Current.Session[sessionKey] == null ? false : true;
            }

        }

        public SessionInfo Instance
        {
            get
            {
                return HttpContext.Current.Session[sessionKey] == null ? null : (SessionInfo)HttpContext.Current.Session[sessionKey];
            }
            set
            {
                HttpContext.Current.Session[sessionKey] = value;
            }
        }



        public void Abandon()
        {

            HttpContext.Current.Session.Abandon();
            HttpContext.Current.Session[sessionKey] = null;
        }

        public void Clear()
        {
            HttpContext.Current.Session.Clear();

        }
    }

My test case is same as the answer below

[TestMethod]
public async Task UpdateDisplayName_Test() {
    //Arrange
    var mySessionAdaptorService = new Mock<ISessionAdaptorService>();

    var controller = new HomeController(userServiceMock.Object, myProfileServiceMock.Object, mySessionAdaptorService.Object);

    var displayName = "display";
    var status = false;
    var id = 1;
    myProfileServiceMock.Setup(m => m.UpdateDisplayName(It.IsAny<string>(), id)).Returns(status);
    mySessionAdaptorService.Setup(m => m.Instance.Id).Returns(id);

    //Act
    var result = await controller.UpdateDisplayName(displayName) as JsonResult;

    //Assert
    Assert.IsNotNull(result); 
}

Code Update. Please find the below code i used for SessionAdapter class and ISessionAdapter Interface and also implementation.please give your suggestions is this correct way.

     public interface ISessionInfo
        {
            string Id { set; get; }
            string Email { set; get; }
            string UserName { set; get; }
            UserDetailsViewModel _userDetailsViewModel { set; get; }
            string permission { set; get; }

            OrganizationViewModels Organization { set; get; }
            List<UserTeamModels> teams { set; get; }
            string status { set; get; }
            string role { set; get; }
            List<string> roles { set; get; }
        }

        public  class SessionInfo : ISessionInfo
        {
            public string Id { set; get; }
            public string Email { set; get; }
            public string UserName { set; get; }
            public UserDetailsViewModel _userDetailsViewModel { set; get; }
            public string permission { set; get; }

            //public string organization { set; get; }
            public OrganizationViewModels Organization { set; get; }
            public List<UserTeamModels> teams { set; get; }
            public string status { set; get; }
            public string role { set; get; }
            public List<string> roles { set; get; }
        }

 public interface ISessionAdapter
    {
        void Clear();
        void Abandon();
        bool DoesSessionExists { get; }
        ISessionInfo Instance { get; set; }

    }


    public class SessionAdapter : ISessionAdapter
    {
        private string sessionKey = "sessionInfoKey";

        public bool DoesSessionExists
        {
            get
            {
                return HttpContext.Current.Session[sessionKey] == null ? false : true;
            }
        }

        public ISessionInfo Instance
        {
            get
            {
                return HttpContext.Current.Session[sessionKey] == null ? null : (SessionInfo)HttpContext.Current.Session[sessionKey];
            }
            set
            {
                HttpContext.Current.Session[sessionKey] = value;
            }
        }

        public void Abandon()
        {

            HttpContext.Current.Session.Abandon();
            HttpContext.Current.Session[sessionKey] = null;
        }

        public void Clear()
        {
            HttpContext.Current.Session.Clear();

        }

Upvotes: 2

Views: 92

Answers (1)

Nkosi
Nkosi

Reputation: 247088

Abstract external dependency and inject it into the controller. As long as it remains static there isn't much else to do about it test-wise

An abstraction can look like this

public interface ISessionAdapterService {
    int Id { get; }
    string DisplayName { get; set; }
}

with the following implementation.

public class SessionAdapterService : ISessionAdapterService {
    public string DisplayName { 
        get { return SessionAdapter.Instance._userDetailsViewModel.display_name; } 
        set { SessionAdapter.Instance._userDetailsViewModel.display_name = value; } 
    }

    public int Id {
        get { return SessionAdapter.Instance._userDetailsViewModel.id; }
    }
}

Controller would need to use abstraction as dependency

[Authorize]
[HttpPost]
public async Task<JsonResult> UpdateDisplayName(string displayname) {
    bool status = _myProfileService.UpdateDisplayName(displayname, sessionAdapterService.Id);

    if (status)
        sessionAdapterService.DisplayName = displayname;

    return Json(new { status = status, displayname = displayname }, JsonRequestBehavior.AllowGet);
}

Assuming sessionAdapterService is an injected ISessionAdapterService

The unit test can now mock the external dependency and inject it into the controller.

[TestMethod]
public async Task UpdateDisplayName_Test() {
    //Arrange
    var mySessionAdaptorService = new Mock<ISessionAdaptorService>();

    var controller = new HomeController(userServiceMock.Object, myProfileServiceMock.Object, mySessionAdaptorService.Object);

    var displayName = "display";
    var status = false;
    var id = 1;
    myProfileServiceMock.Setup(m => m.UpdateDisplayName(It.IsAny<string>(), id)).Returns(status);
    mySessionAdaptorService.Setup(m => m.Id).Returns(id);

    //Act
    var result = await controller.UpdateDisplayName(displayName) as JsonResult;

    //Assert
    Assert.IsNotNull(result);
    dynamic data = result.Data;
    Assert.IsNotNull(data);
    Assert.AreEqual(displayName, (string)data.displayname);
    Assert.AreEqual(status, (bool)data.status);
}

UPDATE.

based on your comments Updated abstraction of the SessionInfo class

public interface ISessionInfo {
    string Id { set; get; }
    string Email { set; get; }
    string UserName { set; get; }
    UserDetailsViewModel _userDetailsViewModel { set; get; }
    string permission { set; get; }

    OrganizationViewModels Organization { set; get; }
    List<UserTeamModels> teams { set; get; }
    string status { set; get; }
    string role { set; get; }
    List<string> roles { set; get; }
}

public class SessionInfo : ISessionInfo { ... }

public interface ISessionAdapterService {
    void Clear();
    void Abandon();
    bool DoesSessionExists { get; }
    ISessionInfo Instance { get; set; } 
}

I would also advise you to review you model design. It is very brittle and forces the session info class to be tightly coupled to implementation concerns.

Upvotes: 4

Related Questions