As usual, I design my domain models, around == and ReferenceEquals() , reference equality is executed. And Equals() fulfilling equality of value. The reason I don't use any of them for identity equality is three times:
Not everything has an identifier , so there may be confusion about how Equals () and == actually work when an object is used without identification. Think, for example, of a cache containing multiple objects, or temporary / auxiliary objects. What about aggregated objects that can be based on several different domain objects? What identity could he compare?
Equality of identity is a subset of the meaning of equality , from my experience when identity equality is involved, equality of equality is not much behind, and usually the value of identity also includes equality of identity. After all, if the identities do not match, are the meanings really the same?
What does equality of identity really mean, say , ask yourself this question: "What does equality of identity mean without context?" Is a user with Id 1 equal to a comment with Id 1? Of course, I hope that this is not so, since both entities are very different.
So, why use any of the built-in equality methods ( == and Equals() ) for something that is an exception, not a rule? Instead, I tend to implement a base class that provides my identity and implements identity equality, depending on how general identity equality is in my current domain.
For instance; in an area where identity equality is very unusual, I would create a custom EqualityComparer<T> to make identity equality when and where necessary, taking into account the context if identity equality is not a common problem in my current domain.
However, in an area where identity equality is very common, I would choose a method in my base identifier class IdentityEquals() that takes care of identity equality at a basic level.
Thus, I disclose only equality of identity, where it is relevant and logical. Without any potential confusion as to how any of my equality checks can work. Be it Equals() , == , or IdentityEquals / EqualityComparer<T> (depending on how common an identity identity is within my domain).
Also, as a note, I recommend reading Microsoft's recommendations for overloading equality .
In particular:
By default, the == operator checks the reference equality to determine if two references point to the same object, so link types do not need to implement the == operator to get this functionality. When the type is immutable, which means the data contained in the instance cannot be changed, overloading the == operator to compare the value of equality instead of reference equality can be useful because, since immutable objects, they can be considered the same as long as they have such same value. The override operator == in immutable types is not recommended.
EDIT:
Regarding Assert.AreEqual and Assert.AreSame your domain defines what equality means; be it reference, personality or value. Thus, your Equals definition in your domain also extends to the Assert.AreEqual definition. If you say that Equals checks for equality of identity, then the logical extension Assert.AreEqual checks for equality of identity.
Assert.AreSame checks if both objects are the same object. Identical and equal are two different concepts. The only way to check if the object referenced by A is the same as the object referenced by B is a reference equality. Semantically and syntactically, both names make sense.