【问题标题】:How to unit test a SharePoint Add-in?如何对 SharePoint 加载项进行单元测试?
【发布时间】:2016-12-14 13:33:33
【问题描述】:

我想删除 SharePoint 依赖项并将它们模拟出来。新的 SharePoint 加载项模板中的默认索引操作如下所示:

    public ActionResult Index()
    {
        User spUser = null;
        var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
        using (var clientContext = spContext.CreateUserClientContextForSPHost())
        {
            if (clientContext != null)
            {
                spUser = clientContext.Web.CurrentUser;
                clientContext.Load(spUser, user => user.Title);
                clientContext.ExecuteQuery();
                ViewBag.UserName = spUser.Title;
            }
        }
        return View();
    }

我尝试将 ClientContext 打包到适配器中,但无法模拟出 Web 属性:

public interface IClientContext
{
    Web Web { get; }
    void Load<T>(T clientObject, params Expression<Func<T, object>>[] retrievals) where T : ClientObject;
    void ExecuteQuery();
}

public class ClientContextAdapter : IClientContext
{
    private readonly ClientContext _wrappedClient;
    public ClientContextAdapter(ClientContext client)
    {
        _wrappedClient = client;
    }

    public Web Web => _wrappedClient.Web;

    public void Load<T>(T clientObject, params Expression<Func<T, object>>[] retrievals) where T : ClientObject
    {
        _wrappedClient.Load(clientObject, retrievals);
    }
    public void ExecuteQuery()
    {
        _wrappedClient.ExecuteQuery();
    }
}

如何对 SharePoint 加载项进行单元测试?

【问题讨论】:

    标签: c# asp.net-mvc unit-testing sharepoint tdd


    【解决方案1】:

    找到了解决方案,因此可以通过以下方式模拟 SharePoint 依赖项。 Web 也应该打包到适配器中:

    public interface IWeb
    {
        User CurrentUser { get; }
    }
    
    public class WebAdapter : IWeb
    {
        private readonly Web _wrappedClient;
        public WebAdapter(Web client)
        {
            _wrappedClient = client;
        }
    
        public User CurrentUser => _wrappedClient.CurrentUser;
    }
    

    ClientContext 适配器,内部带有 Web 适配器:

    public interface IClientContext
    {
        IWeb Web { get; }
        void Load<T>(T clientObject, params Expression<Func<T, object>>[] retrievals) where T : ClientObject;
        void ExecuteQuery();
    }
    
    public class ClientContextAdapter : IClientContext
    {
        private readonly ClientContext _wrappedClient;
        public ClientContextAdapter(ClientContext client)
        {
            _wrappedClient = client;
        }
    
        public IWeb Web => new WebAdapter(_wrappedClient.Web);
    
        public void Load<T>(T clientObject, params Expression<Func<T, object>>[] retrievals) where T : ClientObject
        {
            _wrappedClient.Load(clientObject, retrievals);
        }
    
        public void ExecuteQuery()
        {
            _wrappedClient.ExecuteQuery();
        }
    }
    

    通过穷人的依赖注入从 HomeController 中移除 ClientContext 依赖:

         IClientContext _clientContext;
    
        #region Constructors
        public HomeController()
        {
            // Called by MVC
        }
    
        public HomeController(IClientContext clientContext)
        {
            _clientContext = clientContext;
        }
        #endregion
    
        [SharePointContextFilter]
        public ActionResult Index()
        {
            if (_clientContext == null)
            {
                var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
                _clientContext = new ClientContextAdapter(spContext.CreateUserClientContextForSPHost());
            }
    
            if (_clientContext != null)
            {
                User spUser = _clientContext.Web.CurrentUser;
                _clientContext.Load(spUser, user => user.Title);
                _clientContext.ExecuteQuery();
                ViewBag.UserName = spUser.Title;
            }
    
            return View();
        }
    

    使用 Moq 和 FluentAssertions 对 Index 操作进行单元测试:

    [TestClass]
    class HomeControllerTests
    {
        private HomeController _homeController;
    
        [TestInitialize]
        public void Init()
        {
            // Arrange
            var user = new User(new ClientContext("http://localhost"), 
                new ObjectPathConstructor(new ClientContext("http://localhost"), string.Empty, null));
            user.Title = "TestUser";
            var mockWeb = new Mock<IWeb>();
            mockWeb.SetupGet(w => w.CurrentUser).Returns(user);
            var mockClient = new Mock<IClientContext>();
            mockClient.SetupGet(c => c.Web).Returns(mockWeb.Object);
    
            _homeController = new HomeController(mockClient.Object);
        }
    
        [TestMethod]
        public void Index()
        {
            // Act
            var result = (ViewResult)_homeController.Index();
    
            // Assert
            result.Should().BeViewResult();
            string userName = result.ViewBag.UserName;
            userName.Should().Be("TestUser");
        }
    }
    

    【讨论】:

    • 您是否也为 File / FileInformation 类实现了类似的适配器?
    猜你喜欢
    • 2017-04-14
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 2019-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多