question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Applying customizations from base class or interface fails in 4.0.0-rc1 (regression)

See original GitHub issue

The following tests succeed in AutoFixture 3.51.0 but fail in 4.0.0-rc1: (even in the latest commit in master: c856cd6)

[Fact]
public void ShouldApplyCustomizationsFromBaseClass()
{
    var fixture = new Fixture();
    fixture.Customize<BaseClass>(c => c.Without(bc => bc.Id));
    var res = fixture.Create<ImplClass>();
    Assert.Equal(0, res.Id);
}

[Fact]
public void ShouldApplyCustomizationsFromInterface()
{
    var fixture = new Fixture();
    fixture.Customize<IInterface>(c => c.Without(bc => bc.Id));
    var res = fixture.Create<ImplClass>();
    Assert.Equal(0, res.Id);
}

public interface IInterface
{
    int Id { get; set; }
}

public class BaseClass
{
    public int Id { get; set; }
}

public class ImplClass : BaseClass, IInterface
{

}

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:11 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
zvirjacommented, Jan 31, 2018

Thanks for raising the question. Well, this is the desired change and it has been applied on purpose.

Previously we had an issue when customization of one sub-type could affect other sub-type. For instance:

class Base { public string Common { get; set; } }
class Child1: Base { }
class Child2: Base { }

[Fact]
public void EnsureCustomizationAreNotAffected()
{
    var fixture = new Fixture();
    fixture.Customize<Child1>(c => c.With(x => x.Common, "dummy"));

    var result = fixture.Create<Child2>();

    Assert.NotNull(result.Common);
}

In the v3 this test failed, causing a lot of confusion to people. As you might imagine, the scenarios were more complicated and it was very non-obvious why the particular members are not initialized.

For instance, the following code will not work, which again proves that API is not designed for that.

fixture.Customize<Base>(c => c.With(x => x.Common, "foo"));

Therefore, in order to fix that issue we changed the approach, so that now customization of one type cannot affect other types, even if they belong to the same inheritance line. As you might see in that PR, it fixed a bunch of usability issues and added more clarity (while the change is indeed breaking).

If you still would like to omit base/interface properties, you could use the following snippet:

private class SamePropertySpecification : IRequestSpecification
{
    private readonly Type _declaringType;
    private readonly string _name;

    public SamePropertySpecification(Type declaringType, string name)
    {
        _declaringType = declaringType;
        _name = name;
    }

    public bool IsSatisfiedBy(object request)
    {
        if (request is PropertyInfo pi)
        {
            return pi.DeclaringType == this._declaringType &&
                   pi.Name.Equals(this._name, StringComparison.Ordinal);
        }

        return false;
    }
}

[Fact]
public void TestBasePropertyOmitting()
{
    var fixture = new Fixture();
    
    fixture.Customizations.Add(new Omitter(new SamePropertySpecification(typeof(Base), nameof(Base.Common))));

    var result = fixture.Create<Child1>();
    Assert.Null(result.Common);
}

If you need that feature frequently, you could create your own extension method for fixture. However, I’d vote to not have such a feature out-of-the-box, as it looks very confusing.

1reaction
nphmullercommented, Nov 22, 2017

In this case we use AutoFixture as a test data generator for Entity Framework integration tests.

We have a couple of base types or interfaces that our entities use that contain common properties. Id, tenant-id (and navigation property), stuff like that.

For example, one of these properties is which user created the object. This property is not that interesting for most tests, and if it was generated it would create a huge graph (the User class also has many navigation properties) that would have to be generated and inserted into the database. This would make the test slow or even fail at db level because the object wasn’t meant to be inserted that way.

So it’s easier to simply exclude these properties and opt-in when necessary. At base class level, because else the same omit rule would have to be written for every entity type.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why is it possible to implement an interface method in base ...
Because every time I implement some interface I should check if each method in this interface "interferes" with the base class methods. If...
Read more >
Release Notes for Zabbix 4.0.0rc1
Zabbix is an enterprise-class open source distributed monitoring solution. ... This document contains the release notes for Zabbix 4.0.0rc1.
Read more >
Allow profiles to define a base/parent profile [#1356276]
Allowing install profiles to declare base profiles (just like themes can declare base themes) would drastically simplify customizations to ...
Read more >
changelog.txt
... access failure * internal MergedBeanDefinitionPostProcessors apply after all ... from parent bean definition now * introduced SmartLifecycle interface ...
Read more >
JupyterLab Changelog — JupyterLab 4.1.0a0 documentation
Previously, users had to customize settings separately for each type of cell, the file editor, and the console editor. Now, you can change...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found