Before you file a bug, have you:
Tried upgrading to newest version of Fluent Assertions, to see if your issue has already been resolved and released?
Already at the latest version (5.10.3)
Checked existing open and closed issues, to see if the issue has already been reported?
Did a quick search and found nothing of interest.
Tried reproducing your problem in a new isolated project?
Yes, reproducible.
Read the documentation?
Yes, which may hint to use ComparingByMembers.
Considered if this is a general question and not a bug?. For general questions please use StackOverflow.
I am not sure if it should be categorized as the former or the later.
RSAParameters equivalency check seems to fail, even though the parameters are exactly the same if you compare the original parameters and the compared ones. It succeeds if we use the ComparingByMembers<RSAParameters>() option, even though RSAParameters seems to only hold public properties as byte[]:
public struct RSAParameters
{
public byte[]? D;
public byte[]? DP;
public byte[]? DQ;
public byte[]? Exponent;
public byte[]? InverseQ;
public byte[]? Modulus;
public byte[]? P;
public byte[]? Q;
}
I have the following extension method to do a deep copy of an object, using Newtonsoft.Json:
public static class SystemExtensions
{
public static TObject DeepCopy<TObject>(this TObject @object)
where TObject : class, new()
{
string serializedObject = JsonConvert.SerializeObject(@object);
return JsonConvert.DeserializeObject<TObject>(serializedObject);
}
}
And the following test class, in a xUnit test project, where RsaContainer holds RSAParameters as a public property:
using System.Security.Cryptography;
using FluentAssertions;
using UnitTests.Common.Extensions;
using Xunit;
namespace RsaParametersTest
{
public class UnitTest1
{
[Fact]
public void Test1()
{
// Arrange
using var rsa = RSA.Create();
var original = new RsaContainer
{
Parameters = rsa.ExportParameters(true)
};
RsaContainer compared = original.DeepCopy();
// Act & Assert
// Works
original.Should().BeEquivalentTo(compared, opts => opts.ComparingByMembers<RSAParameters>());
// "Broken"
original.Should().BeEquivalentTo(compared);
}
private class RsaContainer
{
public RSAParameters Parameters { get; set; }
}
}
}
Considering RSAParameters doesn't override ToEqual, I would expect BeEquivalentTo to work without any overrides.

If equivalency assertion options are left untouched, the comparison fails and the test breaks.

N/A
RSAParameters is a struct, which means it'll implement Equals automatically by comparing the values of the properties. But since those properties are arrays, and arrays themselves do not override Equals, you end up doing a reference equality check between two arrays, which will never match.
The ComparingByMembers option ensures that FA will do the comparison of the arrays itself.
@dennisdoomen I see, thanks for the clarification! Is there a way to configure this globally as part of a xUnit project that you would know of?
Yes, you can set this as a global option as explained here.
I've already seen this, but there is no easy way to setup global options with xUnit.
For people that would look for an alternative, I've implemented an extension method to "patch" that behavior:
public static EquivalencyAssertionOptions<TComparedObject> ConfigureRsaParametersEquivalencyCheck<TComparedObject>(this EquivalencyAssertionOptions<TComparedObject> opts)
{
return opts.ComparingByMembers<RSAParameters>();
}
var original = new A();
var compared = new A();
compared.Should().BeEquivalentTo(original, opts => opts.ConfigureRsaParametersEquivalencyCheck());
Most helpful comment
I've already seen this, but there is no easy way to setup global options with xUnit.
For people that would look for an alternative, I've implemented an extension method to "patch" that behavior:
Setup
Usage