与参数并行运行 nunit 测试(nunit 3.8.x)



我想并行运行我的硒测试,并在我的程序集中设置以下内容.cs。

[assembly: Parallelizable(ParallelScope.Fixtures)]

好的,好的。这行得通。

下面是代码结构的简短示例

using NUnit.Framework;
namespace MyExample
{
[TestFixture]
[Category("TestsRunningWithLogin1")]
public class Test_Example1
{
[Test, Order(1)]
public void Test1()
{
}
[Test, Order(2)]
public void Test2()
{
}
}
[TestFixture]
[Category("TestsRunningWithLogin2")]
public class Test_Example2
{
[Test, Order(1)]
public void Test1()
{
}
[Test, Order(2)]
public void Test2()
{
}
}
}

测试需要用户名和密码,并在网页中执行某些操作。登录等当前在 OneTimeSetUp 方法中处理。网页在用户设置中保存上次使用的视图。

如果我按顺序运行测试,我没有问题,因为测试不会相互影响。所有测试都可以使用相同的用户名运行。

如果我并行运行它,它们可能会相互影响。例如,test1 配置了一个视图,在 test2 中不应该看到什么。

我的想法是与不同的用户一起运行类(其中有很多)。当测试开始时,它应该采用一个用户名,并行运行测试当前未使用该用户名。目前我不知道哪些测试正在由 nunit 并行运行,所以我无法直接参数化它们。

我没有找到任何如何控制并行测试的方法。我可以定义是否并行以及并行执行的数量。我想要的是,给出并行运行测试参数。如果我有 3 个并行运行的测试类,我想给出所有 3 个不同的参数。

有什么想法可以做到这一点吗?

使用单例模式根据线程 ID 从一组密码中分配怎么样?

快速解释,

IThreadCredentials是一个描述凭据的接口,无论它们在您的情况下是什么样子。

ThreadCredentials是我编写的一个简单的类,它实现了IThreadCredentials。

ICredentialManager 是一个描述如何分配和返回凭据的接口。

CredentialManager.Instance 是在灯具之间共享的单一实例,用于借用和归还凭据。

public interface IThreadCredentials
{
string UserName { get; }
string Password { get; }
}
public class ThreadCredentials : IThreadCredentials
{
public ThreadCredentials(string userName, string password)
{
this.UserName = userName;
this.Password = password;
}
public string UserName { get; }
public string Password  { get; }
}
public interface ICredentialManager
{
IThreadCredentials GetCredentialsFromPool();
void ReturnCredentialsToPool();
}
public sealed class CredentialManager : ICredentialManager
{
private static readonly Lazy<CredentialManager> lazy = new Lazy<CredentialManager>(() => new CredentialManager());
private static readonly object syncRoot = new object ();
private static readonly Queue<IThreadCredentials> availableCredentialQueue = new Queue<IThreadCredentials>();
private static readonly IDictionary<int, IThreadCredentials> credentialsByThread = new Dictionary<int, IThreadCredentials>();
private CredentialManager()
{
IEnumerable<IThreadCredentials> availableCredentials = new[]{new ThreadCredentials("Foo", "FooPassword"), new ThreadCredentials("Bar", "BarPassword")};
foreach (IThreadCredentials availableCredential in availableCredentials)
{
availableCredentialQueue.Enqueue(availableCredential);
}
}
public static CredentialManager Instance => lazy.Value;
public IThreadCredentials GetCredentialsFromPool()
{
return GetCredentialsFromPool(Thread.CurrentThread.ManagedThreadId);
}
public void ReturnCredentialsToPool()
{
ReturnCredentialsToPool(Thread.CurrentThread.ManagedThreadId);
}
private static IThreadCredentials GetCredentialsFromPool(int threadId)
{
lock (syncRoot)
{
IThreadCredentials result;
if (credentialsByThread.TryGetValue(threadId, out result))
{
return result;
}
// This presupposes you have enough credentials for the concurrency you are permitting 
result = availableCredentialQueue.Dequeue();
credentialsByThread.Add(threadId, result);
return result;
}
}
private static void ReturnCredentialsToPool(int threadId)
{
lock (syncRoot)
{
if (credentialsByThread.ContainsKey(threadId))
{
IThreadCredentials credentials = credentialsByThread[threadId];
credentialsByThread.Remove(threadId);
availableCredentialQueue.Enqueue(credentials);
}
}
}
}

用法:

在测试夹具设置中,您可以执行以下操作:

IThreadCredentials credentials = CredentialManager.Instance.GetCredentialsFromPool();
// Now you can use credentials for whatever

在拆解中,您可以

CredentialManager.Instance.ReturnCredentialsToPool();
// Then promise you stop using those credentials

显然,当您打算并行运行线程时,您至少需要拥有可用凭据的数量,否则您将在取消排队时出现异常。

使用 nunit TestCase("data") 属性 例:

[TestCase("differentUserName", "password")]
public void MyTest(string username, string password)          
{  
// Test steps
}

没有 nunit 的一个可能的答案是提供参数的小服务。因此,每个并行测试都应该调用一个 Web 服务,并将获得其唯一的参数。Web 服务将在每次调用时返回下一个参数集。

如果我提供 10 个不同的参数集,并行运行 3 个测试,我可以肯定,这 3 个并行测试永远不会得到相同的参数。假设所有测试用例需要几乎相同的时间。

我会称之为黑客,因此我要求一个 nunit 解决方案。

最新更新