Consider removing ISerializable support #2506
Replies: 5 comments 29 replies
-
I personally think that the intrinsic types are enough. I can't remember ever looking or needing more than that. So from my POV, your first alternative would be fine. |
Beta Was this translation helpful? Give feedback.
-
I prefer ability to run individual theory rows individually. But - is that limitation due to Visual Studio Test Explorer being lame? I use ReSharper so I don't know if this would affect me. What problem are you solving by removing this? EDIT: I see the problem.
A lot easier to read discussions on Desktop than mobile phone... |
Beta Was this translation helpful? Give feedback.
-
this would break a few things for me. But all of those can be worked around. And IMO removing ISerializable support is a good idea to remove the associated complexity |
Beta Was this translation helpful? Give feedback.
-
It is extremely important for me to be able to run theory rows individually. Currently I am using
You can see in the above classes I am using custom serialisation for some properties. My tests do use the same types returned by the TheoryData. For example: https://github.com/finlabsuk/open-banking-connector/blob/02f1b903321d07e59e60d3cca60a95a228902269/test/OpenBanking.Library.Connector.BankTests/BankTests/GenericHostAppTests.cs#L24-L47 Would be very disappointing to lose either ability to run theory rows individually or even ability to customise labelling in test runner by grouping in classes as above.... |
Beta Was this translation helpful? Give feedback.
-
I've pushed up into The implementation supports:
Anything not on this list won't be supported; in particular, the generic collection class like Just as important, since types are still embedded (albeit safely now, see discussion below), this will not impact the parameter types you can use; you are still able to use things like Based on the discussion here, this implementation does a safe(r) form of type embedding in the serialization: rather than always embedding type names it uses a type index, and we only embed full types names for enums and Hopefully this will address the concerns with the loss of flexibility by rolling back the I haven't merged this into |
Beta Was this translation helpful? Give feedback.
-
Update: July 6, 2022
The solution I landed on includes removing the type-unsafe serialization format in favor of a mostly lookup table-based type system, while still supporting serialization of enums and
IXunitSerializable
objects with embedded type information. This limits the type-embedded serialization to just those two cases, and we verify that we are only creating enums or classes that implementIXunitSerializable
when deserializing. Since this interface was designed explicitly only for unit testing with xUnit.net (and it's not an arbitrary serialization interface likeISerializable
), this should alleviate any potential security concerns. In practice, this should not noticeably change the kinds of data that v3 can serialize when compared to v2, but it should be done in a much safer manner (and without relying on any unsafe built-in serialization infrastructure), and it should be both more memory efficient and higher performance. You can read more about this below.Description of the issue
Currently we use
BinaryFormatter
to support serializing arbitrary test case data across process boundaries. This replaces support forIXunitSerializable
from v2 (which was added because the lowest common denominator of target frameworks for v2 does not includeISerializable
). This serializer is used today to allow arbitrary data to be passed to test cases via theory rows, and allow the end user to run those individual theory rows in Visual Studio's Test Explorer. Without some kind of serialization support, we would end up reverting back to xUnit.net v1 behavior (one Test Explorer item per test method, which runs all the associated data rows without the ability to run individual rows independently of one another).Binary serialization has been deprecated because of security concerns and will be outright removed from future versions of .NET. Other related serializers (SoapFormatter, LosFormatter, NetDataContractSerializer, ObjectStateFormatter) suffer from the same concerns. A quick analysis of the serialization in v2 shows that it, too, suffers from the arbitrary type deserialization concern.
Generally speaking, we have two alternatives.
1. Remove generalized object serialization
If we were to remove generalized object serialization, that would mean that any test method which contains unsupported objects in a theory row would revert to the v1 behavior in Test Explorer (this is also what happens today in v2 for arbitrary objects which do not implement
IXunitSerializable
).What types would be supported in box? Likely the list would look very much like what we support intrinsically in v2. Any data row which contains data outside this supported type list would still be supported, but would lose the ability in Test Explorer to run individual data rows.
2. Add support for a safer serialization alternative
There are some safer alternatives (such as
XmlSerializer
) which would allow test authors to implement serialization that would be supported, but an important caveat would be that these serialization formats do not support polymorphism.What does that mean? In practical terms: if the object in your data row is of type
Employee
, then your test method argument must also be of typeEmployee
: trying to use base types (likePerson
) or interfaces (likeIPerson
) would not be supported. During the discovery process, we would have to look for exact type matches between data row element and test method signature, and fall back to the non-serialized behavior when they don't match.Additionally, there is no good single serialization system to support, since every one of these safer serializers tends to come with its own set of features, limitations, and contracts for how serialization is defined (most tend to use attributes). These feature sets and contracts are not cross-serializer. So it's very likely that we would have to pick just a single (or very small number) of these serializers to support, as we would not be equipped to support an arbitrary number of them.
We could also re-introduce support for something like
IXunitSerializable
but with the new exact-type-match requirements.Thoughts
Please provide thoughts on this in this discussion thread. Should we support any kind of arbitrary object serialization? If so, would you prefer something built-in like
XmlSerializer
(and which one?), or would you prefer us to keepIXunitSerializable
but with the new same-type restrictions?Thanks!
Beta Was this translation helpful? Give feedback.
All reactions