Testing PersonFirstName class as a Value Object For reference:


  A Value Object is an immutable type that is distinguishable only by the state of its properties. That is, unlike an Entity, which has a unique identifier and remains distinct even if its properties are otherwise identical, two Value Objects with the exact same properties can be considered equal. 


Please see the code below: 

public class PersonFirstName
{
    //public string FirstName { get; set; }

    private string _firstName;

    public PersonFirstName(string firstName)
    {
        if (firstName == null)
            throw new ArgumentNullException("Surname");
        if (!PersonFirstName.IsValid(firstName))
            throw new ArgumentException("Invalid value.", "Surname");
        this._firstName = firstName;
        FirstName = firstName;
    }

    public PersonFirstName() //for NHibernate
    {
    }

    public static bool IsValid(string candidate)
    {
        if (string.IsNullOrWhiteSpace(candidate))
            return false;
        if (candidate.Length &gt; 255)
            return false;
        return true;
    }

    public string FirstName
    {
        get { return _firstName; }
        private set 
        {
            _firstName = value; 
        }
    }

    public override bool Equals(object obj)
    {
        PersonFirstName PersonFirstName = obj as PersonFirstName;
        if (ReferenceEquals(PersonFirstName, null))
            return false;
        return _firstName == PersonFirstName.FirstName;
    }

    public override int GetHashCode()
    {
        return _firstName.GetHashCode();
    }
}


and the Unit Test below:

[Test]
public void Domain_FirstNameValue_ValueObjectCreated()
{
    //Arrange
    var PersonFirstName1 = new PersonFirstName("Ian");
    var PersonFirstName2 = new PersonFirstName("Ian");
    //Act
    var firstNameCompareResult = PersonFirstName1.Equals(PersonFirstName2);
    //Assert
    Assert.True(firstNameCompareResult);
}


I would be grateful for comments on the quality of this test.
A few notes:


The argument exceptions contain an incorrect parameter name ("Surname"). Use nameof(firstName) instead: this allows the compiler to verify that you're referencing an existing identifier, and the refactoring tools of your IDE can automatically update it when you rename that parameter.
Why are you setting both this._firstName and FirstName in the constructor? That's doing double work.
A read-only automatic property seems appropriate here: public string FirstName { get; }. This can only be assigned within a constructor, similar to readonly fields, and doesn't require you to explicitly create a backing field.
I see a disabled property with a public setter. If it wasn't disabled, then FirstName instances could not guarantee that their GetHashCode would always return the same value. That could lead to subtle bugs such as failing dictionary lookups, so you did well to make your class immutable.
You may want to implement IEquatable&lt;T&gt;. It's not a replacement for Equals and GetHashCode, but it lets you provide a strongly-typed equality check, which can prevent unnecessary type-checks or boxing/unboxing, and it clearly signals intent. Likewise, if you need to order or sort these first-names, take a look at IComparable and IComparable&lt;T&gt;.
Why does IsValid not allow names longer than 255 characters? If there's a good reason for that, then why isn't it documented? And does that restriction always apply, or only in a certain context? And is a simple false or ArgumentException sufficient for the caller, or do they need to distinguish between different validation failures?
The test method is incorrectly named: according to the name, it's testing object creation, but it's actually testing equality. Domain_EqualFirstNameValues_Equals would be more accurate.
Assert.True has an overload that accepts a failure message. A good message (perhaps including the values that are involved) can make it easier to determine why a test is failing.