Refreeze or how to remove a customization

Jun 22, 2011 at 8:23 AM

Hi

I sometimes have the need to do something like this:

 

var company1 = fixture.Freeze<Company>()

var user1 = fixture.CreateAnonymous<User>();

 

var company2 = fixture.Freeze<Company>();

var user2 = fixture.CreateAnonymous<User>();

 

Where the Company is re-freezed for subsequent calls to CreateAnonymous(). It's often not as simple as this, and there's a lot of setup done one the fixture beforehand, else I would just use two fixtures.

I just wonder if it's possible to refreeze - or if there's a better solution to the problem?

I've looked at Inject() for implementing it myself, but I see no way to remove a customizations once it's added. 

 

Have a nice day! :)

//Asger

Coordinator
Jun 22, 2011 at 6:05 PM

My first, although probably most useless, answer is: if you feel the need to do this, your test setup code is too complex. This, once again, strongly indicates that your System Under Test is too coarse-grained. Consider refactoring.

But assuming that you really need this feature: this isn't easy to do with the current API, but here's a couple of suggestions:


Could you possibly resolve all the instances first and then inject them along the way? Like this:

[Fact]
public void RefreezeHack()
{
    // Fixture setup
    var fixture = new Fixture();
    var version2 = fixture.CreateAnonymous<Version>();
    var version1 = fixture.Freeze<Version>();
    // Exercise system
    fixture.Inject(version2);
    var actual = fixture.CreateAnonymous<Version>();
    // Verify outcome
    Assert.Equal(version2, actual);
    // Teardown
}

The above unit test succeeds.


Another alternative is to look at the fixture.Customizations property. Basically, when you Freeze or Inject something it'll end up as an item in the Customizations property, so what you could also do is take a snapshot of it before and use a diff to figure out which one to remove afterward. Something like this:

[Fact]
public void UnfreezeHack()
{
    // Fixture setup
    var fixture = new Fixture();
    var snapshot = fixture.Customizations.ToList();
    var anonymousVersion = fixture.Freeze<Version>();
    var freezer = fixture.Customizations.Except(snapshot).Single();
    // Exercise system
    fixture.Customizations.Remove(freezer);
    var expected = fixture.Freeze<Version>();
    var actual = fixture.CreateAnonymous<Version>();
    // Verify outcome
    Assert.Equal(expected, actual);
    // Teardown
}

 

This unit test actually passes.


However, I don't think it would be too hard to implement Unfreeze as a 'real' feature, so I'm going to create a feature request out of this.

Coordinator
Jun 22, 2011 at 6:07 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Jun 27, 2011 at 1:36 PM

Thank you very much for your reply. I'm sorry I'm late, but notifications got flagged as spam.

For context (and because it doesn't add value to the feature request) I'm putting my reply here, hope that's ok.

First of all I agree that the test setup might be too complex, but I was trying to make a small integration test - I don't know if that's going too far away from the intent of autofixture :)

I would sure like Unfreeze as a feature, but the RefreezeHack above does the trick very well. 

Thanks again!

Jun 27, 2011 at 1:44 PM

Thinking about it, the "new" WithFactory method used as described here (http://autofixture.codeplex.com/discussions/231342) might also do the trick in my case, because I can force the user to be given the correct company (as it is a ctor argument) and still get autofixtures as the rest of the arguments - or at least it seems so (still need to try it out).

I don't know why I did not see that before :)

That said Unfreeze is still relevant for when it's not such a simple case with a constructor argument.