zoukankan      html  css  js  c++  java
  • 使用MSTest

    背景

    在代码框架越来越复杂,需求变更越来越快的时代,往往一个项目需要很多人合作完成,这就会涉及到很多的refactor,refactor过程中,往往会对现有代码造成不必要的bug。所以单元测试以及集成测试就显得非常重要,这边介绍下.net下使用使用MSTest编写unit test和integration test。

    创建一个专门用于测试的project,添加如下包

    然后就可以使用TestClass,TestMethod等特性来测试代码了,NSubstitute是一个很方便的mock工具,可以在构建各种interface的mocking(new出来的对象请不要使用)。

    执行

    MSTest中有多个特性,ClassInitialize, ClassCleanup, TestInitialize, TestMethod(包括DataTestMethod), TestCleanup

    在执行一个或多个TestMethod标注的方法时,ClassInitialize最先执行,ClassCleanup最后执行,对于每一个TestMethod,执行顺序是TestInitialize,TestMethod,TestCleanup。

    substitute Returns 任何变量的用法

    当参数是一个object对象的时候,切记要使用Arg.Any,因为一旦两个对象不同,那么得到的值也不同

            [TestMethod]
            public void FileNameIsNullWhenNoFilesAvailable()
            {
                var dataStreamProvider = Substitute.For<IDataStreamProvider>();
                dataStreamProvider.GetFileNamesAsync(Arg.Any<string>()).Returns(Task.FromResult(Empty<string>.Enumerable));
    
                var unitUnderTest = Create(dataStreamProvider: dataStreamProvider);
    
                Assert.IsNull(unitUnderTest.FileName);
            }    

    举几个DataTestMethod的例子

            [DataTestMethod]
            [DataRow("  123", DisplayName = "Space before")]
            [DataRow("321  ", DisplayName = "Space after")]
            [DataRow("3 000", DisplayName = "Space inside")]
            public void TrimAllWhitespace_RemovesSpaces(string text)
            {
                var trimmed = text.TrimAllWhitespace();
                var result = trimmed.Contains(" ");
                Assert.AreEqual(false, result);
            }    
    
    
            /// <summary>
            /// Test saving the setting of <see cref="CountingConfiguration.LockNumberOfFixReferencePieces"/> by different user.
            /// </summary>
            [DataTestMethod]
            [DynamicData(nameof(BoolPropertiesPermissionsTestData), DynamicDataSourceType.Method)]
            public async Task LockNumberOfFixReferencePieces_RespectsPermission(Permission permission, bool valueToSet, bool expectedResult)
            {
                var securityService = Substitute.For<ISecurityService>();
                securityService.CurrentPermission.Returns(permission);
    
                var service = Create(securityService: securityService);
                var configuration = await service.GetConfigurationToChangeAsync();
    
                await configuration.UpdateSettingAsync(valueToSet, nameof(configuration.LockNumberOfFixReferencePieces));
                await service.CommitConfigurationToChangeAsync();
    
                Assert.AreEqual(expectedResult, configuration.LockNumberOfFixReferencePieces);
            }
    
            private static IEnumerable<object[]> BoolPropertiesPermissionsTestData()
            {
                yield return new object[] { Permissions.Administrator, true, true };
                yield return new object[] { Permissions.Supervisor, true, true };
                yield return new object[] { Permissions.Operator, true, false };
            }

    Test event

    1. 内部事件的测试

    如图,CommandCreatorEventHandle是测试对象unitUnderTest内部的event,该测试将其绑定到一个回调方法中,然后测试该回调是否正常运行

    2. 引用外部对象的事件的测试

    如下代码模拟了ProductionTestUIOperationEventHandler的事件,返回了state,该事件是productionTestInternalUiManagementService的OperationChanged触发的。

    然后由于测试的类command当中绑定了productionTestInternalUiManagementService的OperationChanged事件的回调方法,因此会跳转到回调方法中,从而实现event的测试

            [TestMethod]
            public async Task Execute_CommandSuccess()
            {
                var productionTestInternalUiManagementService =
                    Substitute.For<IProductionTestUIManagementService>();
                var command = TouchTestCommandCreatorTest.Create(Array.Empty<string>(), _channelWriter,productionTestInternalUiManagementService : productionTestInternalUiManagementService);
                Assert.IsNotNull(command);
                var task = command.ExecuteAsync(CancellationToken.None);
                var uiOperationResult = new ProductionTestUIOperationResult(ProductionTestUIOperationExecutingResult.Success);
                var state = new ProductionTestUIOperationState(ProductionTestUIOperation.TouchTest,
                                                              ProductionTestUIOperationStateTrigger.ResponseFromClient,
                                                              uiOperationResult);
                productionTestInternalUiManagementService.OperationChanged +=
                    Raise.Event<ProductionTestUIOperationEventHandler>(state);
                var result = await task;
                Assert.AreEqual(ProductionTestCommandResultStatus.Pass, result.Result);
                Assert.AreEqual("TOUCH A
    ", await ReadFromChannelAsync());
            }

    测试某个对象执行了某个方法

    await classObject.Received().methodName(Arg.Any<string>());

    善用TaskCompletionSource

            [TestMethod]
            public async Task CurrentDataUpdatedAndEventRaised()
            {
                var completionSource = new TaskCompletionSource<bool>();
    
                var unitUnderTest = CreateSuccessfulConfiguration(20);
                unitUnderTest.CurrentDataChanged += LocalHandler;
    
                await unitUnderTest.StartAsync();
                await unitUnderTest.StartByRefXAsync(10);
    
                var eventRaised = await Task.WhenAny(completionSource.Task, Task.Delay(AsyncTestHelper.TaskCompletionTimeout))
                                  == completionSource.Task;
    
                Assert.IsTrue(eventRaised);
                Assert.IsNotNull(unitUnderTest.CurrentData);
    
                void LocalHandler(CountingData countingData)
                {
                    completionSource.SetResult(true);
                }
            }    

    当测试UI线程的viewModel时,比如UWP会用到CoreDispatcher,这时候需要使用TaskCompletionSource来封装,最终获取它设置的result来测试

  • 相关阅读:
    Vue内敛模板
    vue自定义组件添加原生事件监听
    vue 组件开发 props 验证
    Vue中子组件数据跟着父组件改变和父组件数据跟着子组件改变的方法
    jQuery中outerWidth()方法
    CSS3-transition
    行内元素(例如)设置float之后才能用width调整宽度
    leetcode LRU Cache python
    opcache effect
    leetcode Same Tree python
  • 原文地址:https://www.cnblogs.com/xiaojidanbai/p/14199514.html
Copyright © 2011-2022 走看看