New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Run test methods within a fixture in parallel #164
Comments
Update: Both this comment and the following one were in reply to an individual who apparently removed his own comments. I'm leaving my answers. Well it's in the spec and scheduled for post-3.0 implementation. If it were so easy, we probably would have done it. Not sure what connection you see with mbunit. The fact that they had it doesn't help us. |
This is getting a bit tiresome. A few points, already stated but apparently missed...
I find your talk of "reverse engineering" very disturbing. Open source is only possible in a context where copyright is respected. So if you are suggesting that we might ignore the mbunit licensing terms, you are way off base. |
While I did contribute many patches to MbUnit and used it for years, I was As for reverse engineering, there isn't really any use here. NUnit works
|
A much more tactful comment than mine! Our current priorities in the world of parallel execution are:
This seems to represent the order of greatest usefulness to users. I'll also mention that marking something as post-3.0 does not necessarily mean the feature comes at a later time than it would if we made it part of 3.0. Rather, it may mean that 3.0 comes at an earlier point in time. |
When we do this, we are going to have to decide how to handle setup and teardown commands. The easiest option would likely be to construct the test class for each test so that there is no contention for data. |
I would favor making that an option at some point anyway, but I'm not sure whether it's a run option or a fixture-by-fixture (attributed) option or both. |
Hi! |
@julianhaslinger NUnit 3.4 will be out at the end of the month, so no, this feature will not be included. FYI, this issue is in our Backlog milestone (or pseudo-milestone) rather than 3.4 because we are following a practice of only adding a small number of key defining issues to each numbered milestone in advance. The next milestone, 3.6, is scheduled to drop in 3 more months, which probably sounds discouraging to you. :-( However, if you see this issue being merged to master, you will be able to get an earlier drop from our MyGet feed. |
@chris-smith-zocdoc Yes, that's exactly what I'm doing. I created a new type of work item, |
Haven't read everything too carefully, but one thing I'd like to request as part of this feature is that the parallelism be "smart", especially for I/O bound tests. For example, if you have 10 threads executing 100 parallelizable tests, it shouldn't be the case that the 10 threads sit and wait for the first 10 tests to complete before moving on to the next 10 tests. If the first 10 tests start awaiting very long-running I/O tasks, then the threads should be free to move on to other tests. When the I/O tasks complete, threads will resume the awaiting tests as threads free up. Basically, I'm asking for smart throughput management for I/O bound tests that make extensive use of async/await. This is our number one bottleneck in tests, by far. |
@chris-smith-zocdoc In fact, that's pretty much what I'm doing. I'm essentially using the existing countdown mechanism to trigger dispatch of a one time teardown task. The trick is to get it dispatched on the proper queue. @gzak Bear in mind that the mechanism for parallel execution already exists. It depends on workers independently pulling tasks rather than having a controller that pushes tasks to workers. So if one worker is busy with a task for a while, other workers will continue to execute other tasks independently. The trick is to set the number of workers based on the nature of the tests being run. NUnit does fairly well by default with normal, compute-bound unit tests but other sorts of tests may require the user setting an appropriate level of parallelism. |
Can someone explain me how does it work? |
You figured it out! Yes, all tests in a fixture use the same instance. This is historical with NUnit, which has always worked that way. You must choose between running the test cases in parallel and having any state that is modified per test. There is no way around it currently. That said, if you have a decent proportion of fixtures, simply running fixtures in parallel can give you good performance. |
@agray Yes, in fact that's the only reason I have an AssemblyInfo.cs now. |
@agray The one you asked about: [Parallelizable(ParallelScope.Children)] |
don't forget target [assembly: Parallelizable(ParallelScope.Children)] |
@LirazShay I use NUnit to drive Selenium tests, and was using fixture-level fields to hold things like references to user accounts and to the Selenium WebDriver instance that I was working with and so was unable to run tests in parallel in-fixture. The way I worked around that was to write a "factory" (I use quotes because I'm not sure it's the right term) that implements IDisposable that for each test encapsulates all my test needs and cleanly tears them down at the end of the test with no need for [TearDown] or [OneTimeTearDown] kind of like so:
Then, within a test I can do this:
This way, I can avoid a lot of code duplication, and if I ever need to change the dependencies of my test I just do it once in the factory. If anyone has feedback on the strategy I took I'd appreciate it! |
@tparikka I highly recommend exactly that approach myself. |
I haven't looked into using If your tests are not CPU-bound, higher makes sense. But as always with perf- the answer is so dependent on your scenario that it's better to measure rather than guess. |
@CharliePoole I'm using [TestFixture]
class Deserialization
{
public static IEnumerable<TimeSpan> ShouldDeserializeAllCases() => Enumerable.Repeat(0, 5).Select(x => TimeSpan.FromSeconds(2));
[TestCaseSource("ShouldDeserializeAllCases"), Parallelizable(ParallelScope.Children)]
public void ShouldDeserializeAll(TimeSpan t)
{
Thread.Sleep(t);
Assert.AreEqual(1, 1);
}
} The overall time taken is 10 seconds instead of ~2. |
I'll think that there are no children, so in this case, you could better use |
@ParanoikCZE Thanks. I'm actually flying blind with respect to what that attribute means, so I've tried all enum values on there. Regardless of which of I just tried moving it to the class, but this doesn't seem to help either. |
Try this is source of inspiration :)
|
@ParanoikCZE Thanks again. I tested this out in Visual Studio and the visualization is much clearer, but the tests are still running sequentially. Easier to see this if you use a constant sleep for each testcase instead of increasing steps. |
Try adding [assembly: LevelOfParallelism(5)] into AssemblyInfo, I think there is some default value, but maybe it doesn't work for you somehow. Anyway, I'm out of ideas. :) |
Currently, we only have implemented parallel execution at the fixture level. It should be possible to run individual methods of a fixture in parallel as well as individual test cases for a parameterized method.
We should be able to specify the exact level of parallelism on the fixture or method.
This issue was previously part of #66
The text was updated successfully, but these errors were encountered: