简体   繁体   中英

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

        }

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM