可以在LINQPad中使用xUnit吗?
如果能够先在LINQPad中编写某些概念的测试,那将是非常好的。这比添加另一个ConsoleApp23423894238来快速编写单元测试要容易得多。
是的,可以在LinqPad中使用xUnit。我已经更新了这个答案,为您提供最新的信息,但我之前给出的原始答案也为您提供了一些关于使用xUnit的见解和链接,因此我将其保留供您参考。
Query
/ Add XUnit Test Support
内置了XUnit支持。这将添加一个查询和所需的样板代码通过#load引用,因此您可以立即开始测试事实和理论。private::Tests
区域内放置它):#region private::Tests
[Theory]
[InlineData(1)]
[InlineData(3, 6)]
[InlineData(5, 7, 9)]
void OddNumbers(params int[] values)
{
static bool IsOdd(int value) => value % 2 == 1;
foreach (var value in values)
{
Assert.True(IsOdd(value), $"IsOdd({value}) is false");
}
}
#endregion
按下Alt+Shift+T运行所有测试并检查结果。
注意:第一次添加XUnit测试支持时,它还会向您的查询目录添加一个文件XUnit.linq
- 这是一个小型库,用于支持xUnit测试,除非您确切地知道自己在做什么,否则不要触碰它。例如,您可以修改此文件以更改测试摘要的显示方式(例如,您可以向方法RunTests添加参数Func<UserQuery.TestResultSummary, bool> filter = null
并在查询内部添加.Where(filter)
,如果filter不为null,则允许您过滤测试摘要的结果)。
例如:RunTests(filter: f => f.MethodName.StartsWith("Unit"));
将仅显示名称以“Unit”开头的测试摘要。
你可以修改 LinqPad 6 提供的 xunit
脚本来支持可跳过的单元测试(NUGET 包 XUnit.SkippableFact
,详细描述请参见本答案末尾的“动态跳过测试和理论”链接)。
在 xunit 中进行以下更改:
函数 RunTests - 添加: runner.OnTestSkipped = info => AddTestResult(info);
类 TestResultSummary - 添加: public bool Skipped() => _testInfo is Xunit.Runners.TestSkippedInfo;
类 TestResultSummary / public object Status - 添加: _testInfo is Xunit.Runners.TestSkippedInfo ? Util.WithStyle ("Skipped", "color:orange") :
这些更改将使 xunit
脚本能够在结果中显示测试被跳过的情况。
要测试它,请通过 F4 加载 NUGET 包 XUnit.SkippableFact
,然后添加测试框架并最后添加测试:
[SkippableFact]
void Test_Xunit3()
{
Skip.If(true, "skipping");
Assert.True(1 + 1 == 2);
}
[SkippableTheory]
[InlineData(1)]
[InlineData(2)]
void Test_Xunit4(int x)
{
Skip.If(x==2, "skipping");
Assert.True(1 + 1 == 2);
}
注意: 这些更改也适用于普通的XUnit。因此,将更改添加到代码中不会对其造成影响。
两个答案指引了我正确的方向,但是描述不够完整,所以我不得不进行一些实验。为了节省您的时间,我将描述我所做的事情;我现在有适用于LinqPad 5和LinqPad 6(以及7)的工作解决方案。
基于Tom所写的内容,我能够让LinqPad 5(v5.42.01)正常工作。
还需要一些更多的步骤,这些步骤并不明显,也没有在被接受的答案中解释清楚,所以我会描述一下我是如何解决的。
首先,您需要使用付费版本的LinqPad,因为只有这样才能加载NUGET包。
要在LinqPad中加载所需的包,请按F4。查询属性对话框会打开。在该对话框中,单击Add NUGET...。
NUGET对话框会打开。在NUGET对话框的中间,有一个搜索文本框。搜索xUnit.Net
- 一旦它显示出来,点击Add to query,等待它加载完成,然后点击Add namespaces.然后对Xunit.Runner.LinqPad.
做同样的操作。
然后关闭NUGET对话框,但保持查询属性打开。您需要在其中进入高级选项卡:启用(勾选)"将所有非框架引用复制到单个本地文件夹中。"现在可以关闭查询属性对话框了。
将以下示例导入到查询编辑器中(C#程序
模式):
void Main()
{
// Press F4, go to Advanced, then
// tick-mark "Copy all non-framework references to a single local folder"
var me = Assembly.GetExecutingAssembly();
var result = Xunit.Runner.LinqPad.XunitRunner.Run(me);
result.Dump("Xunit runner result");
}
/// <summary>
/// This test class is there for demo purpose, so developers can
/// see how to write test methods.
/// It also verifies that XUnit itself is functioning correctly.
/// </summary>
public class A_XUnitSelfTest
{
[InlineData(2)]
[InlineData(3)]
[Theory]
public void Test_Theory(int a)
{
Assert.True(a == 2 || a == 3); // succeeds
}
[Fact]
public void Test_Fact()
{
Assert.False(1 == 0); // succeeds
}
}
运行它,您将看到测试运行器的输出。
运行3个测试中的3个...
已完成:3个测试,用时0.003秒(0个失败,0个跳过)
修改测试以查看测试失败的情况,方法是将Test_Fact()
中的assert更改为Assert.False(1 == 1);
,然后再次运行它。这次应该显示:
运行3个测试中的3个...
[FAIL] UserQuery+A_XUnitSelfTest.Test_Fact: Assert.False() Failure
期望值:False
实际值:True
在Xunit.Assert.False(Nullable`1 condition, String userMessage)位置
在Xunit.Assert.False(Boolean condition)位置
在C:\Users...\AppData\Local\Temp\LINQPad5_oyxxqxbu\query_mxsmky.cs的UserQuery.A_XUnitSelfTest.Test_Fact()中的第62行
已完成:3个测试,用时0.005秒(1个失败,0个跳过)
LinqPad 6 与众不同,因为它基于 .NET Core,因此需要不同的库。
从这里开始:
void Main()
{
// Press F4, go to Advanced, then
// tick-mark "Copy all non-framework references to a single local folder"
var me = Assembly.GetExecutingAssembly();
var result = Xunit.Runner.LinqPad.XunitRunner.Run(me);
result.Dump("Xunit runner result");
}
/// <summary>
/// This test class is there for demo purpose, so developers can
/// see how to write test methods.
/// It also verifies that XUnit itself is functioning correctly.
/// </summary>
public class A_XUnitSelfTest
{
[InlineData(2)]
[InlineData(3)]
[Theory]
public void Test_Theory(int a)
{
Assert.True(a == 2 || a == 3); // succeeds
}
[Fact]
public void Test_Fact()
{
Assert.False(1 == 0); // succeeds
}
}
xUnit.net
、xUnit.net [Core Unit Testing Framework]
和xUnit.net [Runner Utility]
及其所有命名空间,最后将XUnit运行器源代码由@ramiroalvarez提到复制到上面的xUnit测试示例末尾:
在F4对话框的高级选项卡中启用“将所有Nuget程序集复制到单个本地文件夹”...那应该就足够了,但事实并非如此,请继续阅读:GetTargetAssemblyFilename
中):if (shadowFolder != xunitFolder
|| Directory.GetFiles(shadowFolder, "xunit.execution.*.dll").Length == 0)
{
throw new InvalidOperationException("Please enable the shadow folder option ...");
}
// ...
var targetAssembly = Path.Combine(shadowFolder, Path.GetFileName(assemblyFilename));
//Console.WriteLine($"Copy \"{ assemblyFilename }\" -> \"{ targetAssembly }\"");
File.Copy(assemblyFilename, targetAssembly, true);
注释这些行
// ...
// throw new InvalidOperationException("Please enable the shadow folder option ...");
// ...
// File.Copy(assemblyFilename, targetAssembly, true);
然后你就完成了!(已在LinqPad 6版本v6.8.3 X64上测试)
提示 1:
您可以按照描述将xUnit运行器附加到代码中,但在LinqPad 6中有一种更优雅的方式:
将仅包含xUnit.Runner源代码的副本保存在与您的单元测试文件相同的路径上,并使用文件名xUnit.Runner.LinqPad6.linq
。
然后,在您的测试代码顶部添加以下内容:
现在您已经清理了您的代码!每次创建新测试时,只需记得添加#load
命令。
提示 2:
为了能够静态跳过事实,请向测试运行器的代码添加以下两个属性:
/// <summary>
/// Skip a Fact (you can override it by setting OverrideSkip=true)
/// </summary>
public class SkipFactAttribute : FactAttribute
{
/// <summary>
/// Override SkipFact: Set OverrideSkip=true to run even skipped tests
/// </summary>
public static bool OverrideSkip = false; // set to true to ignore skip
/// <summary>
/// Constructor. Used to set skip condition.
/// </summary>
public SkipFactAttribute()
{
if (!OverrideSkip) Skip = "Skipped Fact";
}
}
/// <summary>
/// Skip a Theory (you can override it by setting OverrideSkip=true)
/// </summary>
public class SkipTheoryAttribute : TheoryAttribute
{
/// <summary>
/// Override SkipTheory: Set OverrideSkip=true to run even skipped tests
/// </summary>
public static bool OverrideSkip = false; // set to true to ignore skip
/// <summary>
/// Constructor. Used to set skip condition.
/// </summary>
public SkipTheoryAttribute()
{
if (!OverrideSkip) Skip = "Skipped Theory";
}
}
[Fact]
替换为[SkipFact]
或将[Theory]
替换为[SkipTheory]
。[SkipFact]
或类似的[SkipTheory]
,除了你当前正在编写的那个测试。public class TestsFixture : IDisposable
{
public TestsFixture() // running once before the tests
{
// true: Ignore Skip and run all tests, false: Skip is effective
SkipFactAttribute.OverrideSkip = true;
SkipTheoryAttribute.OverrideSkip = true;
}
public void Dispose() // running once, after the tests
{
// teardown code
}
}
[Fact]
/[Theory]
属性,并将.OverrideSkip
变量设置回false
。如果您想了解有关使用xUnit进行单元测试的高级主题,我建议阅读以下内容:
如果您想在Visual Studio中使用它,可以在这里找到信息。
可能吗?有点。
这既不是LINQPad的主要用例,也不是单元测试的主要用例。
关于LINQPad,您可以使用现有的测试运行程序,但可能唯一可以与LINQPad集成的是控制台运行程序。测试运行程序并不是一个微不足道的程序。请尝试 Xunit.Runner.LinqPad。
至于需要“为正在设计的概念编写一些测试”,请考虑如果您没有发现它们足够有价值而创建一个项目并将其保留在源代码控制中,则可能无法从您的单元测试工作流程中获得足够的价值。获取更多价值的一种方法是使用行为驱动开发(BDD),如果您想以业务可读语言编写要求,请尝试类似于SpecFlow的东西。
https://github.com/asherber/Xunit.Runner.LinqPad/blob/master/Xunit.Runner.LinqPad/XunitRunner.cs
在查询属性中,重要的是勾选“将所有NuGet程序集复制到单个本地文件夹”,否则您会遇到以下错误:“InvalidOperationException:请为非框架引用启用影子文件夹选项”。我刚试图打开一个LINQPad查询文件,尝试加载xunit
包,但出现了一个错误,这在我使用LINQPad多年来从未发生过。所以我的答案是不。