-
Notifications
You must be signed in to change notification settings - Fork 338
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
Fix parameter freezing when used in combination with Passive Attributes (#637, xUnit.net2) #665
Conversation
/// <paramref name="parameter"/> or <paramref name="matcher"/> is null. | ||
/// </exception> | ||
public FreezeOnMatchCustomization( | ||
ParameterInfo parameter, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking on this change, I can predict a question similar to this one I've been asked earlier. Despite it does solve the original issue, I cannot come up with any self contained use case for the new constructor. I tend to create a new internal version of the FreezeOnMatchCustomization
in the Glue Library and move there all the changes from this class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, yes, sort of. I'm predictable, it seems 😐
Sorry to be a bit negative, but I think this needs to go in a slightly different direction. The overall idea, however, seems sound 👍
Adding a ParameterInfo
property pulls in the direction of less cohesion, which I'm not particularly fond of. Now the class has two properties, both of which could be null
, or both of which, according to the type system, could have a value. This is the sort of feature extension that tends to rot a code base over time.
Some time ago, @ecampidoglio and I had a discussion about something similar that might be worth revisiting. Essentially, the idea is to widen the existing 'greedy' constructor, so that it takes any object
, instead of only a Type
. AFAICT, there's nothing in the class's invariants that require it to be a Type
.
Given that we now seem to have a use for this change, I think it might be worthwhile pursuing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to be a bit negative, but I think this needs to go in a slightly different direction.
That's totally fine. I found a potential fix, we just need to give it a proper shape ;)
I reviewed the discussion you mentioned, thanks for sharing that with me. That is a possible solution but if I understand correctly, the TargetType
property and both existing constructors (?) in the FreezeOnMatchCustomization
class will need to be obsoleted.
I'm still validating other possible solutions. As a POC, I created a new internal freezing customization. It allows not to change the existing deep-seated API but it brings some other challenges with testing internals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late reply but I'm currently on vacation and have only occasional access to the Internet. ☀️🍦
Looking back at the discussion, I noticed that @ploeh did, in fact, predict this exact scenario:
Based on this, I'm inclined to keep it as is. However, I was wondering if we'd then be missing out on some opportunities, like:
new FreezeOnMatchCustomization(somePropertyInfo); new FreezeOnMatchCustomization(someParameterInfo); new FreezeOnMatchCustomization(someFieldInfo); // etc.
Unfortunately, I failed to follow up on that comment so the blame is totally on me. 😔
In the face of this new requirement, I agree that relaxing the constructor of FreezeOnMatchCustomization
sounds like the right thing to do.
Of course, we would still have to pay the complexity tax of handling multiple variants of the target
parameter. Although it would be nice if we could restrict the subset of types that can be passed as arguments through the type system, in the end, I'm afraid it would still have to be object
since there is no other contravariant type between PropertyInfo
, ParameterInfo
, FieldInfo
and Type
.
I should mention that I'm saying all this without having researched other possible solutions that don't involve modifying the constructor of FreezeOnMatchCustomization
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is no other contravariant type between
PropertyInfo
,ParameterInfo
,FieldInfo
andType
.
Well, there's Albedo, which was created to address that particular problem... 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. Albedo does the job!
JFI, AutoFixture Core and all the test framework Glue Libraries have to reference it.
4fa5dee
to
e365d88
Compare
The build error looks intimidating:
Unfortunately I cannot reproduce it locally because of another build error with NUnit3 (even in the latest
|
Does that mean that somebody has coupled Fixture "80 times" and I'm the lucky man who has to decouple this? 😨 |
The issue is caused by the new Moving the graph initialization to another class(es) will just postpone the problem for a while. AutoFixture is designed in such a way that extending the range of supported specimen types often leads to referencing new types in the |
d1e63ed
to
648ffd1
Compare
@@ -6,6 +6,9 @@ | |||
<title>AutoFixture</title> | |||
<authors>Mark Seemann</authors> | |||
<owners>Mark Seemann</owners> | |||
<dependencies> | |||
<dependency id="Albedo" version="[1,2)" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the correct dependency configuration? The actual dependency added is Albedo 1.0.1, but if I understand this configuration correctly, any 1.x version is supported - including 1.0.0.
Additionally, why exclude a hypothetical version 2 of Albedo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I choose Albedo 1.0.1 simply because it was already referenced in unit tests. I overlooked that the dependency is added to the publicly visible AutoFixture package which should reference the lowest possible version (1.0.0).
I'll get back on this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it ought to reference the lowest possible version that we know works. If we're using 1.0.1, we should state that as a requirement.
If we wish to be able to state that 1.0.0 is the minimum version supported, we should downgrade our use of Albedo so that we are, in fact, testing against that version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything works fine with Albedo 1.0.0.
BTW, there is AutoFixture.Igioms package which is already published with Albedo v1.0.1 dependency. There should be no harm in downgrading this reference to v1.0.0. Please let me know if you have any concerns about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have consistent versions for shared dependencies. If AutoFixture.Idioms works with Albedo 1.0.0, I think it'd be more correct to downgrade its dependency as well. I haven't tested, but looking at the change between 1.0.0 and 1.0.1, I think you're correct that it ought to work as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably start with a separate pull request for that.
6c3b8c5
to
093d80c
Compare
093d80c
to
3b217a3
Compare
@sergeyshushlyapin When it comes to PRs, we generally prefer to have a linear history over merge commits. Could you please remove the merge commits f3c74f9 18fb59d and instead rebase your We – the maintainers – could also do it ourselves once the PR is complete, if you prefer. |
No problem, usually I also prefer rebasing over merge commits. I just noticed that rebasing often "collapse" old conversations, so I just tried to preserve them ;) |
…k for the same parameter
using the ReflectionElement property as a 'request' for creating specimens
3b217a3
to
0d3b877
Compare
since it is not required in this package anymore. Albedo is referenced by AutoFixture package.
0d3b877
to
13513fb
Compare
/// </summary> | ||
public IReflectionElement ReflectionElement { get; } | ||
|
||
/// <summary> | ||
/// The <see cref="Type"/> of the frozen specimen. | ||
/// </summary> | ||
public Type TargetType { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we deprecate the TargetType
property?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not used in AutoFixture anymore. Yes, I think it can be deprecated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR changes some core classes (FreezeOnMatchCustomization) as well as Glue Library classes (xUnit2.FrozenAttribute). I started it as xUnit.net2 contribution and intended to fix all the other libraries with follow up requests.
If I deprecate the TargetType
property and corresponding constructors (which are in 'core'), then other libraries start failing:
1) Building C:\sc\autofixture\Src\AutoFixture.NUnit2.sln failed with exitcode 1.
2) CS0618: FrozenAttribute.cs(113,20): 'FreezeOnMatchCustomization.FreezeOnMatchCustomization(Type, IRequestSpecification)' is obsolete: 'This constructor has been deprecated. Please use constructor that takes IReflectionElement parameter.'
What is the best approach to go? Should I suppress the error in other libraries for the time being or postpone obsoleting the property and constructors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The property is still valid for other Glue Libraries, so it's too early to make it obsolete.
It's looking good 👍 The only comment I have is about deprecation of the the |
I apologize if this feedback comes in late, but I have given this some more thought and I'd like to raise a couple of concerns. By making If we're also going to deprecate the constructor that takes These are my concerns. What are your thoughts? |
From Albedo site:
Won't we end up with Albedo2 inside AutoFixture if we decide to extend the existing core API? |
Since some Albedo maintainers are also AutoFixture maintainers, and since it follows Semantic Versioning, it shouldn't be that bad of an idea if we add it as a dependency... AutoFixture has relied only on BCL, but I can't currently see disadvantages if we'd have to take Albedo as a dependency 😕 |
One thing worth mentioning (according to my understanding, correct me if I'm wrong) is that the |
We're discussing two different issues here.
AutoFixture already depends on Albedo. My point is that, up until now, Albedo has been used internally to simplify the implementation of AutoFixture – the consumers don't need to know or care about Albedo in order to use AutoFixture – but with this PR we're effectively surfacing Albedo as part AutoFixture's public API. The practical effect is that whoever needs to use the Now, if Albedo was a namespace within AutoFixture that wouldn't be much of a problem. But since Albedo is currently published as an external general-purpose package, I see a problem in tying it to AutoFixture's public API.
Well, the On a more philosophical level, I see customizations and specimen builders as AutoFixture's building blocks, combined together to offer functionality that is then conveniently exposed through a higher level API (see the That's why I would rather see that the building blocks themselves continue to be free from dependencies on external libraries. |
From Albedo we need just three things: |
0c8a5f5
to
f860adf
Compare
@sergeyshushlyapin Isn't that much simpler to extend the Another point is extensibility. If later we will need support freezing of another request sources (e.g. PropertyInfo), we will need to create one more wrapper and relay. Eventually, we could end up in wrapper/relay pairs for all type of requests the fixture support. Such perspective doesn't look attractive. It seems that root of your approach is some kind of semantic meaning, but I don't see it. Given that P.S. Also, usage of P.P.S. Excuse me, if I missed something obvious. |
I don't think that is the case. Relays are widely used in AutoFixture and according to test execution results there are no performance issues.
That is one of the three mostly discussed options:
If we talk about Albedo than yes, we will. But are such scenarios numerous?
Yep. The |
f860adf
to
13513fb
Compare
The value proposition offered by Albedo is that it enables a client to model a variety of Reflection types in such a way that they look like they have a common consumption interface: This also forces a client (developer) to consider how to deal with all of the concrete None of these features are in play in this pull request. Instead, the two proposed relays perform type tests and use the downcast objects to access the underlying Reflection objects. In this case, I can't see that wrapping Thus, I don't see that this particular use of Albedo adds any value, and thus I don't think that the added dependency is warranted. In order to prevent more thrashing on this particular PR branch, I'm going to close it. @sergeyshushlyapin, as the owner of the fork, you still have the commits, so you should be able to salvage the good parts of this PR from the commits that introduce Albedo, so I'm not saying that everything in this PR is useless. Quite the contrary, and I'd welcome a second attempt, but I think it ought to be in a fresh PR. I do realise that if anyone is responsible for introducing Albedo to this work item, it's me:
I wrote this in response to the assertion that there's no polymorphic type that can model both The thought of making AutoFixture itself depend on Albedo is not foreign to me. If it's warranted, I'd be happy to entertain the idea (while still listening to arguments against the notion). I'd consider it warranted if it simplifies the user-aimed API of AutoFixture. |
Addresses issue #637 for xUnit.net2 Glue Library.