зеркало из https://github.com/microsoft/testfx.git
Refactor unnecessary try/catch (#4057)
Co-authored-by: Amaury Levé <amauryleve@microsoft.com>
This commit is contained in:
Родитель
c203c4603a
Коммит
bde4e5aabe
|
@ -414,23 +414,22 @@ internal class AssemblyEnumerator : MarshalByRefObject
|
|||
|
||||
// This code is to discover tests. To run the tests code is in TestMethodRunner.ExecuteDataSourceBasedTests.
|
||||
// Any change made here should be reflected in TestMethodRunner.ExecuteDataSourceBasedTests as well.
|
||||
try
|
||||
{
|
||||
data = dataSource.GetData(methodInfo);
|
||||
data = dataSource.GetData(methodInfo);
|
||||
|
||||
if (!data.Any())
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DynamicDataIEnumerableEmpty, "GetData", dataSource.GetType().Name));
|
||||
}
|
||||
}
|
||||
catch (ArgumentException) when (MSTestSettings.CurrentSettings.ConsiderEmptyDataSourceAsInconclusive)
|
||||
if (!data.Any())
|
||||
{
|
||||
if (!MSTestSettings.CurrentSettings.ConsiderEmptyDataSourceAsInconclusive)
|
||||
{
|
||||
throw dataSource.GetExceptionForEmptyDataSource(methodInfo);
|
||||
}
|
||||
|
||||
UnitTestElement discoveredTest = test.Clone();
|
||||
// Make the test not data driven, because it had no data.
|
||||
discoveredTest.TestMethod.DataType = DynamicDataType.None;
|
||||
discoveredTest.DisplayName = dataSource.GetDisplayName(methodInfo, null) ?? discoveredTest.DisplayName;
|
||||
|
||||
tests.Add(discoveredTest);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,16 +78,6 @@ internal class DynamicDataOperations : IDynamicDataOperations
|
|||
_dynamicDataDeclaringType.FullName));
|
||||
}
|
||||
|
||||
if (!data.Any())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
FrameworkMessages.DynamicDataIEnumerableEmpty,
|
||||
_dynamicDataSourceName,
|
||||
_dynamicDataDeclaringType.FullName));
|
||||
}
|
||||
|
||||
// Data is valid, return it.
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -311,19 +311,18 @@ internal class TestMethodRunner
|
|||
{
|
||||
isDataDriven = true;
|
||||
IEnumerable<object?[]>? dataSource;
|
||||
try
|
||||
{
|
||||
// This code is to execute tests. To discover the tests code is in AssemblyEnumerator.ProcessTestDataSourceTests.
|
||||
// Any change made here should be reflected in AssemblyEnumerator.ProcessTestDataSourceTests as well.
|
||||
dataSource = testDataSource.GetData(_testMethodInfo.MethodInfo);
|
||||
|
||||
if (!dataSource.Any())
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DynamicDataIEnumerableEmpty, "GetData", testDataSource.GetType().Name));
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is ArgumentException && MSTestSettings.CurrentSettings.ConsiderEmptyDataSourceAsInconclusive)
|
||||
// This code is to execute tests. To discover the tests code is in AssemblyEnumerator.ProcessTestDataSourceTests.
|
||||
// Any change made here should be reflected in AssemblyEnumerator.ProcessTestDataSourceTests as well.
|
||||
dataSource = testDataSource.GetData(_testMethodInfo.MethodInfo);
|
||||
|
||||
if (!dataSource.Any())
|
||||
{
|
||||
if (!MSTestSettings.CurrentSettings.ConsiderEmptyDataSourceAsInconclusive)
|
||||
{
|
||||
throw testDataSource.GetExceptionForEmptyDataSource(_testMethodInfo.MethodInfo);
|
||||
}
|
||||
|
||||
var inconclusiveResult = new TestResult
|
||||
{
|
||||
Outcome = UTF.UnitTestOutcome.Inconclusive,
|
||||
|
|
|
@ -33,7 +33,7 @@ public enum DynamicDataSourceType
|
|||
/// Attribute to define dynamic data for a test method.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||
public sealed class DynamicDataAttribute : Attribute, ITestDataSource
|
||||
public sealed class DynamicDataAttribute : Attribute, ITestDataSource, ITestDataSourceEmptyDataSourceExceptionInfo
|
||||
{
|
||||
private readonly string _dynamicDataSourceName;
|
||||
private readonly DynamicDataSourceType _dynamicDataSourceType;
|
||||
|
@ -155,4 +155,14 @@ public sealed class DynamicDataAttribute : Attribute, ITestDataSource
|
|||
data = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
string? ITestDataSourceEmptyDataSourceExceptionInfo.GetPropertyOrMethodNameForEmptyDataSourceException()
|
||||
=> _dynamicDataSourceName;
|
||||
|
||||
string? ITestDataSourceEmptyDataSourceExceptionInfo.GetPropertyOrMethodContainerTypeNameForEmptyDataSourceException(MethodInfo testMethodInfo)
|
||||
{
|
||||
Type? type = _dynamicDataDeclaringType ?? testMethodInfo.DeclaringType;
|
||||
DebugEx.Assert(type is not null, "Declaring type of test data cannot be null.");
|
||||
return type.FullName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
internal static class EmptyDataSourceExceptionInfoExtensions
|
||||
{
|
||||
internal static ArgumentException GetExceptionForEmptyDataSource(this ITestDataSource dataSource, MethodInfo testMethodInfo)
|
||||
=> dataSource is ITestDataSourceEmptyDataSourceExceptionInfo info
|
||||
? info.GetExceptionForEmptyDataSource(testMethodInfo)
|
||||
: new ArgumentException(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
FrameworkMessages.DynamicDataIEnumerableEmpty,
|
||||
"GetData",
|
||||
dataSource.GetType().Name));
|
||||
|
||||
private static ArgumentException GetExceptionForEmptyDataSource(this ITestDataSourceEmptyDataSourceExceptionInfo info, MethodInfo testMethodInfo)
|
||||
=> new(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
FrameworkMessages.DynamicDataIEnumerableEmpty,
|
||||
info.GetPropertyOrMethodNameForEmptyDataSourceException(),
|
||||
info.GetPropertyOrMethodContainerTypeNameForEmptyDataSourceException(testMethodInfo)));
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
internal interface ITestDataSourceEmptyDataSourceExceptionInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the method/property name accessed by this data source.
|
||||
/// For example, for DynamicDataAttribute, that will be attribute argument.
|
||||
/// </summary>
|
||||
string? GetPropertyOrMethodNameForEmptyDataSourceException();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the type name on which the method/property accessed by this data source exists.
|
||||
/// </summary>
|
||||
string? GetPropertyOrMethodContainerTypeNameForEmptyDataSourceException(MethodInfo testMethodInfo);
|
||||
}
|
|
@ -80,13 +80,15 @@ public class DynamicDataAttributeTests : TestContainer
|
|||
_dynamicDataAttribute.GetData(methodInfo);
|
||||
});
|
||||
|
||||
public void GetDataShouldThrowExceptionIfPropertyReturnsEmpty() =>
|
||||
VerifyThrows<ArgumentException>(() =>
|
||||
{
|
||||
MethodInfo methodInfo = _dummyTestClass.GetType().GetTypeInfo().GetDeclaredMethod("TestMethod5");
|
||||
_dynamicDataAttribute = new DynamicDataAttribute("EmptyProperty", typeof(DummyTestClass));
|
||||
_dynamicDataAttribute.GetData(methodInfo);
|
||||
});
|
||||
public void GetDataShouldNotThrowExceptionIfPropertyReturnsEmpty()
|
||||
{
|
||||
MethodInfo methodInfo = _dummyTestClass.GetType().GetTypeInfo().GetDeclaredMethod("TestMethod5");
|
||||
_dynamicDataAttribute = new DynamicDataAttribute("EmptyProperty", typeof(DummyTestClass));
|
||||
IEnumerable<object[]> data = _dynamicDataAttribute.GetData(methodInfo);
|
||||
// The callers in AssemblyEnumerator and TestMethodRunner are responsible
|
||||
// for throwing an exception if data is empty and ConsiderEmptyDataSourceAsInconclusive is false.
|
||||
Verify(!data.Any());
|
||||
}
|
||||
|
||||
public void GetDataShouldThrowExceptionIfPropertyDoesNotReturnCorrectType() =>
|
||||
VerifyThrows<ArgumentNullException>(() =>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
|
@ -11,6 +12,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
|
|||
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
|
||||
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
|
||||
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.TestableImplementations;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using Moq;
|
||||
|
||||
|
@ -40,16 +42,12 @@ public class TestMethodRunnerTests : TestContainer
|
|||
|
||||
public TestMethodRunnerTests()
|
||||
{
|
||||
ConstructorInfo constructorInfo = typeof(DummyTestClass).GetConstructor([])!;
|
||||
_methodInfo = typeof(DummyTestClass).GetMethods().Single(m => m.Name.Equals("DummyTestMethod", StringComparison.Ordinal));
|
||||
var classAttribute = new UTF.TestClassAttribute();
|
||||
_testMethodAttribute = new UTF.TestMethodAttribute();
|
||||
PropertyInfo testContextProperty = typeof(DummyTestClass).GetProperty("TestContext");
|
||||
|
||||
var testAssemblyInfo = new TestAssemblyInfo(typeof(DummyTestClass).Assembly);
|
||||
_testMethod = new TestMethod("dummyTestName", "dummyClassName", "dummyAssemblyName", false);
|
||||
_testContextImplementation = new TestContextImplementation(_testMethod, new ThreadSafeStringWriter(null, "test"), new Dictionary<string, object>());
|
||||
_testClassInfo = new TestClassInfo(typeof(DummyTestClass), constructorInfo, true, testContextProperty, classAttribute, testAssemblyInfo);
|
||||
_testClassInfo = GetTestClassInfo<DummyTestClass>();
|
||||
|
||||
_testMethodOptions = new TestMethodOptions(TimeoutInfo.FromTimeout(200), null, _testContextImplementation, false, _testMethodAttribute);
|
||||
|
||||
|
@ -68,6 +66,15 @@ public class TestMethodRunnerTests : TestContainer
|
|||
ReflectHelper.Instance.ClearCache();
|
||||
}
|
||||
|
||||
private static TestClassInfo GetTestClassInfo<T>()
|
||||
{
|
||||
ConstructorInfo constructorInfo = typeof(T).GetConstructor([])!;
|
||||
PropertyInfo testContextProperty = typeof(T).GetProperty("TestContext");
|
||||
var classAttribute = new UTF.TestClassAttribute();
|
||||
var testAssemblyInfo = new TestAssemblyInfo(typeof(T).Assembly);
|
||||
return new TestClassInfo(typeof(T), constructorInfo, isParameterlessConstructor: true, testContextProperty, classAttribute, testAssemblyInfo);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
|
@ -369,6 +376,56 @@ public class TestMethodRunnerTests : TestContainer
|
|||
Verify(results[1].ResultFiles.ToList().Contains("C:\\temp.txt"));
|
||||
}
|
||||
|
||||
public void RunTestMethodWithEmptyDataSourceShouldFailBecauseConsiderEmptyDataSourceAsInconclusiveIsFalse()
|
||||
=> RunTestMethodWithEmptyDataSourceShouldFailIfConsiderEmptyDataSourceAsInconclusiveIsNotTrueHelper(false);
|
||||
|
||||
public void RunTestMethodWithEmptyDataSourceShouldNotFailBecauseConsiderEmptyDataSourceAsInconclusiveIsTrue()
|
||||
=> RunTestMethodWithEmptyDataSourceShouldFailIfConsiderEmptyDataSourceAsInconclusiveIsNotTrueHelper(true);
|
||||
|
||||
private void RunTestMethodWithEmptyDataSourceShouldFailIfConsiderEmptyDataSourceAsInconclusiveIsNotTrueHelper(bool considerEmptyAsInconclusive)
|
||||
{
|
||||
Mock<PlatformServices.Interface.IReflectionOperations2> existingMock = _testablePlatformServiceProvider.MockReflectionOperations;
|
||||
try
|
||||
{
|
||||
// We want this test to go through the "real" reflection to hit the product code path relevant for the test.
|
||||
_testablePlatformServiceProvider.MockReflectionOperations = null;
|
||||
|
||||
string xml =
|
||||
$$"""
|
||||
<RunSettings>
|
||||
<MSTestV2>
|
||||
<ConsiderEmptyDataSourceAsInconclusive>{{considerEmptyAsInconclusive}}</ConsiderEmptyDataSourceAsInconclusive>
|
||||
</MSTestV2>
|
||||
</RunSettings>
|
||||
""";
|
||||
|
||||
var settings = MSTestSettings.GetSettings(xml, MSTestSettings.SettingsNameAlias, null);
|
||||
MSTestSettings.PopulateSettings(settings);
|
||||
|
||||
var testMethodInfo = new TestableTestMethodInfo(
|
||||
typeof(DummyTestClassEmptyDataSource).GetMethod(nameof(DummyTestClassEmptyDataSource.TestMethod)),
|
||||
GetTestClassInfo<DummyTestClassEmptyDataSource>(),
|
||||
_testMethodOptions,
|
||||
() => throw ApplicationStateGuard.Unreachable());
|
||||
var testMethodRunner = new TestMethodRunner(testMethodInfo, _testMethod, _testContextImplementation);
|
||||
|
||||
if (considerEmptyAsInconclusive)
|
||||
{
|
||||
UnitTestResult[] results = testMethodRunner.RunTestMethod();
|
||||
Verify(results[0].Outcome == AdapterTestOutcome.Inconclusive);
|
||||
}
|
||||
else
|
||||
{
|
||||
ArgumentException thrownException = VerifyThrows<ArgumentException>(() => testMethodRunner.RunTestMethod());
|
||||
Verify(thrownException.Message == string.Format(CultureInfo.InvariantCulture, FrameworkMessages.DynamicDataIEnumerableEmpty, nameof(DummyTestClassEmptyDataSource.EmptyProperty), typeof(DummyTestClassEmptyDataSource).FullName));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_testablePlatformServiceProvider.MockReflectionOperations = existingMock;
|
||||
}
|
||||
}
|
||||
|
||||
#region Test data
|
||||
|
||||
[SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Use through reflection")]
|
||||
|
@ -451,5 +508,15 @@ public class TestMethodRunnerTests : TestContainer
|
|||
public UTFExtension.TestContext TestContext { get; }
|
||||
}
|
||||
|
||||
public class DummyTestClassEmptyDataSource
|
||||
{
|
||||
public static IEnumerable<object[]> EmptyProperty => Array.Empty<object[]>();
|
||||
|
||||
[DynamicData("EmptyProperty")]
|
||||
public void TestMethod(int x)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ internal class TestablePlatformServiceProvider : IPlatformServiceProvider
|
|||
MockTraceListener = new Mock<ITraceListener>();
|
||||
MockTraceListenerManager = new Mock<ITraceListenerManager>();
|
||||
MockThreadOperations = new Mock<IThreadOperations>();
|
||||
TestTools.UnitTesting.DynamicDataProvider.Instance = SourceGeneratorToggle.UseSourceGenerator
|
||||
? new SourceGeneratedDynamicDataOperations()
|
||||
: new DynamicDataOperations();
|
||||
}
|
||||
|
||||
#region Mock Implementations
|
||||
|
|
Загрузка…
Ссылка в новой задаче