Matthew Butt

Identical random values in parallel NUnit test assemblies

Posted in programming by bnathyuw on 16 November 2017

We have some NUnit cross-system test assemblies that run in parallel. They upload files and watch to see how they are processed. We were inserting a randomly generated value into the filenames in an attempt to avoid identically named files overwriting each other.

Unfortunately, this didn’t work, and we saw frequent test failures. In particular, we found that filenames generated by one test assembly were often identical to those generated by another.

I wanted to understand why this was happening, so I did some investigation.

We were getting our values fromTestContext.CurrentContext.Random, which is an instance of NUnit’s Randomizer class.

When we look at the implementation of Randomizer, we see this:

static Randomizer()
{
    InitialSeed = new Random().Next();
    Randomizers = new Dictionary<MemberInfo, Randomizer>();
}

The Randomizer is statically seeded with a value generated by the System.Random class. Because this seed is static, the same sequence of random values is shared by all references to Randomizer within each assembly, producing a sequence of values that are highly likely to be different from each other. However, references to Randomizer in a concurrently running assembly use a different instance and have their own sequence of values with its own seed.

Let’s have a quick look at how System.Random is seeded.

The MSDN documentation tells us:

  • The Random() constructor uses the system clock to provide a seed value. This is the most common way of instantiating the random number generator.

And goes on to warn:

…because the clock has finite resolution, using the parameterless constructor to create different Random objects in close succession creates random number generators that produce identical sequences of random numbers.

It would seem that our two parallel test assemblies often start executing within such a short interval of each other, and that NUnit’s Randomizer is seeded with the same value in each assembly, which means the sequences of values are identical.

There is some discussion of introducing a mechanism for controlling the seeding of Randomizer in NUnit, but in the mean time, the solution to our problem was to seed our own System.Random instances, rather than relying on NUnit’s.

Tagged with: , ,

ActionInvoker method sequence

Posted in programming by bnathyuw on 26 October 2011

In one of the projects I’m playing with, I’m doing a bit of a hack over .NET MVC 3.

I’m providing my own implementation of IActionInvoker, currently by extending ControllerActionInvoker, and as part of this work, I’ve done a quick audit of the methods of this class, and the order they are called in.

I’m reproducing them here, in case it’s useful to anyone else:

  • InvokeAction
  • GetControllerAction
  • FindAction
  • GetFilters
  • InvokeAuthorizationFilters
  • GetParameterValues
  • InvokeActionMethodWithFilters
  • InvokeActionMethod
  • CreateActionResult
  • InvokeActionResultWithFilters
  • InvokeActionResult
Tagged with: , , ,

TPT mapping in Entity Framework CTP 5

Posted in programming by bnathyuw on 13 February 2011

I’ve been working on a little project with MVC 3 and Entity Framework Code-First CTP (community technology preview) 5, and have been implementing TPT (type-per-table) inheritance for the various types of user in the system: Customers, Administrators &c.

Yesterday, I added an Administrator class to my model, and this happened:

Yellow screen of death: “The configured property 'Forename' is not a declared property on the entity 'Administrator'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.”

The exceptions message reads: The configured property ‘Forename’ is not a declared property on the entity ‘Administrator’. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.

All very puzzling, as here is my User class:

public class User
{
	public int Id { get; set; }
	[Display(Name = "Forename"), Required]
	public string Forename { get; set; }
	[Display(Name = "Surname"), Required]
	public string Surname { get; set; }
}

and here is my Administrator class:

public class Administrator:User
{
}

(OK, the Administrator class isn’t terribly useful right now, but I’m just fleshing out the schema at the moment.)

Here, finally, is my Repository class, somewhat abbreviated:

public class Repository : DbContext
{
	protected override void OnModelCreating(ModelBuilder modelBuilder)
	{
		modelBuilder.Entity().ToTable("Administrators");
		modelBuilder.Entity().ToTable("Customers");
	}
	public DbSet Administrators { get; set; }
	public DbSet Customers { get; set; }
	public DbSet Users { get; set; }
}

After some futile reading around, I finally decided to roll back to my previous working version, at which point the yellow screen of death disappeared. And it was at this point that the revelation came to me: one of the changes I had made was to alphabetise my DbSet properties, moving Users past Administrators and Customers.

So I went about adding the Administrator class again, but this time keeping the Users property above those for its subclasses:

public class Repository : DbContext
{
	protected override void OnModelCreating(ModelBuilder modelBuilder)
	{
		modelBuilder.Entity().ToTable("Administrators");
		modelBuilder.Entity().ToTable("Customers");
	}
	// Declare superclass first
	public DbSet Users { get; set; }
	public DbSet Administrators { get; set; }
	public DbSet Customers { get; set; }
}

and as if by magic the application started working again.

Moral

When implementing TPT inheritance in CTP 5, declare the superclass DbSet property before its subclasses.

Tagged with: , , , ,