在 MSTest 中使用继承进行共享测试
Use inheritance in MSTest for shared tests
我正在尝试为 D365 插件和 CodeActivities(两者都是 classes)编写单元测试。每个插件里都有一些小测试应该运行,比如:
[TestMethod]
public void NullLocalPluginContext()
{
XrmFakedContext context = new XrmFakedContext();
Assert.ThrowsException<InvalidPluginExecutionException>(
() => context.ExecutePluginWith<SomePlugin>(null));
}
其中SomePlugin
是要测试的class(每个child不同),不能是抽象的(等待IPlugin
)。例如这里是 child:
中的 CheckDuplicateOrder
[TestClass]
public class CheckDuplicateOrderTest
{
[TestMethod]
public void NullLocalPluginContext()
{
XrmFakedContext context = new XrmFakedContext();
Assert.ThrowsException<Exception>(
() => context.ExecutePluginWith<CheckDuplicateOrder>(null));
}
}
对于这些小型测试,我希望 parent 具有共享测试,但我不知道如何引用 'to-be' child 的目标。
我更喜欢 MSTest,但任何 NuGet 框架都可以接受。
Maybe this helps with understanding
每个插件都有自己的测试class。
每个插件测试 class 都需要基本的。
这些基本测试应该继承自parent(所以它们不会占用space)。
插件:狗、猫、老鼠
插件测试:DogTest、CatTest、MouseTest
BasePluginTest -> 应该有共享测试,其中示例中的 SomePlugin
是 Dog/Cat/Mouse。但我不知道如何引用它。每个插件都会有一个函数 TestWalk() { .. ExecutePluginWith<SomePlugin>}
。 Cat 应该调用 CatTest,Dog 应该调用 DogTest。
免责声明:有些人不喜欢这个,因为它滥用 class 继承来保存代码。它是工作的潜在工具,您可以评估它是否适合您。
这似乎可以通过基础 class 来定义共享测试来实现。也许这样的事情会实现你想要做的事情?
// note: no [TestClass] on this type so it doesn't get discovered by MSTest.
// Probably should also be abstract.
public class SharedTests<T> where T : IPlugin
{
[TestMethod]
public void NullLocalPluginContext()
{
XrmFakedContext context = new XrmFakedContext();
Assert.ThrowsException<Exception>(
() => context.ExecutePluginWith<T>(null));
}
}
您的插件 classes 将继承自此 class:
[TestClass]
public class CheckDuplicateOrderTests : SharedTests<CheckDuplicateOrder>
{
// NullLocalPluginContext test is inherited from the parent type
}
[TestClass]
public class SomeOtherPluginTests : SharedTests<SomeOtherPlugin>
{
// Also has NullLocalPluginContext test inherited, but for testing SomeOtherPlugin
}
与正常的 class 一样,您应该更喜欢组合而不是继承。甚至
尽管测试classes 没有 遵循与正常classes 相同的规则和准则,但这并不意味着我们无法实施它们。
因此,当您觉得您的测试 class 中有一些通用功能时,您应该提取一些测试使用的 class。对于正常的业务,您也会这样做-class,不是吗?
class CommonFunc
{
public static bool NullLocalPluginContext<T, TException>() where T: IPlugIn, TException : Exception
{
XrmFakedContext context = new XrmFakedContext();
try { context.ExecutePluginWith<T>(null)) };
catch (T e) { return true; }
return false;
}
}
[TestClass]
public class CheckDuplicateOrderTests
{
[TestMethod]
public void NullLocalPluginContext()
{
Assert.IsTrue(CommonFunc.NullLocalPluginContext<CheckDuplicateOrder, Exception>(null));
}
}
[TestClass]
public class SomeOtherPluginTests
{
[TestMethod]
public void NullLocalPluginContext()
{
Assert.IsTrue(CommonFunc.NullLocalPluginContext<SomePlugin, InvalidPluginExecutionException>(null));
}
}
如果您想记录在测试框架中抛出的实际异常,您也可以让您的通用方法重新抛出异常,而不仅仅是返回 true
或 false
。
我正在尝试为 D365 插件和 CodeActivities(两者都是 classes)编写单元测试。每个插件里都有一些小测试应该运行,比如:
[TestMethod]
public void NullLocalPluginContext()
{
XrmFakedContext context = new XrmFakedContext();
Assert.ThrowsException<InvalidPluginExecutionException>(
() => context.ExecutePluginWith<SomePlugin>(null));
}
其中SomePlugin
是要测试的class(每个child不同),不能是抽象的(等待IPlugin
)。例如这里是 child:
CheckDuplicateOrder
[TestClass]
public class CheckDuplicateOrderTest
{
[TestMethod]
public void NullLocalPluginContext()
{
XrmFakedContext context = new XrmFakedContext();
Assert.ThrowsException<Exception>(
() => context.ExecutePluginWith<CheckDuplicateOrder>(null));
}
}
对于这些小型测试,我希望 parent 具有共享测试,但我不知道如何引用 'to-be' child 的目标。 我更喜欢 MSTest,但任何 NuGet 框架都可以接受。
Maybe this helps with understanding
每个插件都有自己的测试class。 每个插件测试 class 都需要基本的。 这些基本测试应该继承自parent(所以它们不会占用space)。
插件:狗、猫、老鼠
插件测试:DogTest、CatTest、MouseTest
BasePluginTest -> 应该有共享测试,其中示例中的 SomePlugin
是 Dog/Cat/Mouse。但我不知道如何引用它。每个插件都会有一个函数 TestWalk() { .. ExecutePluginWith<SomePlugin>}
。 Cat 应该调用 CatTest,Dog 应该调用 DogTest。
免责声明:有些人不喜欢这个,因为它滥用 class 继承来保存代码。它是工作的潜在工具,您可以评估它是否适合您。
这似乎可以通过基础 class 来定义共享测试来实现。也许这样的事情会实现你想要做的事情?
// note: no [TestClass] on this type so it doesn't get discovered by MSTest.
// Probably should also be abstract.
public class SharedTests<T> where T : IPlugin
{
[TestMethod]
public void NullLocalPluginContext()
{
XrmFakedContext context = new XrmFakedContext();
Assert.ThrowsException<Exception>(
() => context.ExecutePluginWith<T>(null));
}
}
您的插件 classes 将继承自此 class:
[TestClass]
public class CheckDuplicateOrderTests : SharedTests<CheckDuplicateOrder>
{
// NullLocalPluginContext test is inherited from the parent type
}
[TestClass]
public class SomeOtherPluginTests : SharedTests<SomeOtherPlugin>
{
// Also has NullLocalPluginContext test inherited, but for testing SomeOtherPlugin
}
与正常的 class 一样,您应该更喜欢组合而不是继承。甚至 尽管测试classes 没有 遵循与正常classes 相同的规则和准则,但这并不意味着我们无法实施它们。
因此,当您觉得您的测试 class 中有一些通用功能时,您应该提取一些测试使用的 class。对于正常的业务,您也会这样做-class,不是吗?
class CommonFunc
{
public static bool NullLocalPluginContext<T, TException>() where T: IPlugIn, TException : Exception
{
XrmFakedContext context = new XrmFakedContext();
try { context.ExecutePluginWith<T>(null)) };
catch (T e) { return true; }
return false;
}
}
[TestClass]
public class CheckDuplicateOrderTests
{
[TestMethod]
public void NullLocalPluginContext()
{
Assert.IsTrue(CommonFunc.NullLocalPluginContext<CheckDuplicateOrder, Exception>(null));
}
}
[TestClass]
public class SomeOtherPluginTests
{
[TestMethod]
public void NullLocalPluginContext()
{
Assert.IsTrue(CommonFunc.NullLocalPluginContext<SomePlugin, InvalidPluginExecutionException>(null));
}
}
如果您想记录在测试框架中抛出的实际异常,您也可以让您的通用方法重新抛出异常,而不仅仅是返回 true
或 false
。