How to write service test for UpdateAsync in Microsoft Graph API(在单个请求中将多个成员添加到组)

How to write service test for UpdateAsync in Microsoft Graph API (Add multiple members to a group in a single request)

我正在使用 Microsoft Graph Api 客户端并执行向组添加成员。

文档在这里:- https://docs.microsoft.com/en-us/graph/api/group-post-members?view=graph-rest-1.0&tabs=csharp#example-2-add-multiple-members-to-a-group-in-a-single-request

我已成功达到要求。但是当我为我的服务编写测试时 class 不知道什么以及如何验证它。

我是 API 开发人员的初学者,也是 Microsoft Graph API 的初学者。以下是我的代码,看看并 post 您的建议和意见。可能会有帮助。

服务Class:

public class UserGroupService : IUserGroupService
{
    private readonly IGraphServiceClient _graphServiceClient;

    public UserGroupService(IGraphServiceClient graphServiceClient)
    {
        _graphServiceClient = graphServiceClient;
    }
    
    public async Task AddAsync(string groupId, IList<string> userIds)
    {
        var group = new Group
        {
            AdditionalData = new Dictionary<string, object>()
            {
                {"members@odata.bind", userIds.Select(x => $"https://graph.microsoft.com/v1.0/directoryObjects/{x}") }
            }
        };

        await _graphServiceClient.Groups[groupId].Request().UpdateAsync(group);
    }
}

服务测试:

public class UserGroupServiceTests
    {
        private readonly Fixture _fixture = new Fixture();
        private readonly Mock<IGraphServiceClient> _graphServiceClientMock = new Mock<IGraphServiceClient>();
        private readonly IUserGroupService _userGroupService;

        public UserGroupServiceTests()
        {
            _userGroupService = new UserGroupService(_graphServiceClientMock.Object);
        }
        
        // Settingup GraphClientMock
        private void SetupGraphClientMock(string groupId, IList<string> userIds, Group group)
        {
            var groupRequest = new Mock<IGroupRequest>();

            var groupRequestBuilder = new Mock<IGroupRequestBuilder>();

            groupRequest.Setup(x => x.UpdateAsync(group));

            groupRequestBuilder.Setup(x => x.Request()).Returns(groupRequest.Object);

            _graphServiceClientMock.Setup(x => x.Groups[groupId]).Returns(groupRequestBuilder.Object);
        }
        
        [Fact]
        public async Task AddAsync_GivenValidInput_WhenServiceSuccessful_AddAsyncCalledOnce()
        {
            object result;
            var groupId = _fixture.Create<string>();
            var userIds = _fixture.Create<IList<string>>();
            var dictionary = _fixture.Create<Dictionary<string, object>>();
            dictionary.Add("members@odata.bind", userIds.Select(x => $"https://graph.microsoft.com/v1.0/directoryObjects/{x}"));
            var group = _fixture.Build<Group>().With(s => s.AdditionalData, dictionary).OmitAutoProperties().Create();

            SetupGraphClientMock(groupId, userIds, group);

            await _userGroupService.AddAsync(groupId, userIds);

            //TODO  
            // Need to verify _graphServiceClientMock AdditionalData value == mocking group AdditionalData value which is called once in _graphServiceClientMock.
            // Below implementation done using TryGetValue which return bool, I am really afraid to write test using bool value and compare and I feel its not a right way to write test.
            _graphServiceClientMock.Verify(m => m.Groups[groupId].Request().UpdateAsync(It.Is<Group>(x => x.AdditionalData.TryGetValue("members@odata.bind", out result) == group.AdditionalData.TryGetValue("members@odata.bind", out result))), Times.Once);
            _graphServiceClientMock.VerifyNoOtherCalls();
        }
    }

我想验证 _graphServiceClientMock AdditionalData 值 == 模拟组 AdditionalData 值,它像上面一样在 _graphServiceClientMock 中调用一次。任何人对此都有想法。请post提前comments.Thanks。

基于被测对象和提供的被测成员的简单性,以下示例演示了如何对其进行隔离测试,

public class UserGroupServiceTests {

    [Fact]
    public async Task AddAsync_GivenValidInput_WhenServiceSuccessful_AddAsyncCalledOnce() {
        //Arrange            
        string groupId = "123456";
        IList<string> userIds = new[] { "a", "b", "c" }.ToList();
        string expectedKey = "members@odata.bind";
        IEnumerable<string> expectedValues = userIds
            .Select(x => $"https://graph.microsoft.com/v1.0/directoryObjects/{x}");
        Group group = null;

        Mock<IGraphServiceClient> clientMock = new Mock<IGraphServiceClient>();
        clientMock
            .Setup(x => x.Groups[groupId].Request().UpdateAsync(It.IsAny<Group>()))
            .Callback((Group g) => group = g) //Capture passed group for assertion later
            .ReturnsAsync(group) //To allow async flow
            .Verifiable();

        IUserGroupService _userGroupService = new UserGroupService(clientMock.Object);

        //Act
        await _userGroupService.AddAsync(groupId, userIds);

        //Assert
        clientMock.Verify(); //have verifiable expressions been met
        clientMock.VerifyNoOtherCalls();

        //Using FluentAssertions to assert captured group
        group.Should().NotBeNull();//was a group passed
        group.AdditionalData.Should().NotBeNull()// did it have data
            .And.ContainKey(expectedKey);//and did the data have expected key
        (group.AdditionalData[expectedKey] as IEnumerable<string>)
            .Should().BeEquivalentTo(expectedValues);//are values as expected
    }
}

查看代码注释以了解如何执行测试以验证预期行为。

所使用的 FluentAssertions 的直观性质也应该有助于理解所断言的内容