Auto-implemented Properties
State Related Tests
Earlier in this chapter, you learned that tests related to an object's state are verified by evaluating the field within the class (or base class). Since C# allows you to create Auto-implemented properties, the (backing) field an auto-implemented property creates is not accessible to you. Therefore, the PrivateObject
class is needed to access the auto-generated field.
For the following example, we'll say that the "name" attribute of the Person
class is defined as an Auto-implemented property.
Test Case:
# | Test Case | Test Data | Expected |
---|---|---|---|
4 | Initialize the name | Parameter name: "Kenny", Parameter amountOfMoney: 500 | "Kenny" |
Testing Goal: The goal of this test is to initialize the state of the object and verify it did so correctly.
[TestMethod]
public void Constructor_NameIsKenny_InitializeState()
{
// Arrange
string name = "Kenny";
decimal amountOfMoney = 500;
// Act
Person person = new Person(name, amountOfMoney);
// Reflection
PrivateObject target = new PrivateObject(person);
// Obtain object state
string actual = (string)target.GetProperty("Name");
// Assert
Assert.AreEqual(name, actual);
}
Notes:
- Because this is a state-related test, the
PrivateObject
class is used to gain access to the class' backing field. - The
GetProperty()
method is used to access the backing field created by the auto-implemented property. The argument is the identifier of the property you want to access the backing field for.- Using the
GetField()
method in this context would raise an exception, since the class would not declare a field with the specified identifier.
- Using the
It would not be the proper practice to do the following:
[TestMethod]
public void Constructor_NameIsKenny_InitializeState()
{
// Arrange
string name = "Kenny";
decimal amountOfMoney = 500;
// Act
Person person = new Person(name, amountOfMoney);
// Obtain object state
string actual = person.Name;
// Assert
Assert.AreEqual(name, actual);
}
Notes:
- This test does not test the unit in isolation.
Modifying State
Depending how a class is designed, you may experience situations where you cannot initialize the object to the specific state you need for the test using any of the constructor methods defined in the class.
As previously mentioned, you must avoid invoking other parts of the class in your test, so using the set
accessor of a property would be forbidden. It is also possible that the set
accessor may not be defined or accessible.
When faced with this situation, you will use the PrivateObject
class to modify the state of the object without invoking any of its class members.
The following test determines that when you ToggleOscillation()
to a Fan
while it is currently oscillating, the state will change such that it is no longer oscillating. When a Fan
is initialized, it is always not oscillating. None of the constructors in the Fan
class allow you to change this state. In order to verify that the ToggleOscillation()
performs its task correctly, the Fan
must be oscillating before the ToggleOscillation()
method is invoked.
It should also be noted that the IsOscillating
property is auto-implemented.
[TestMethod]
public void ToggleOscillation_TurnOffOscillation_UpdateState()
{
// Arrange
OscillatingFan fan = new OscillatingFan();
PrivateObject target = new PrivateObject(fan);
target.SetProperty("IsOscillating", true);
// Act
fan.ToggleOscillation();
// Assert
bool expected = false;
bool actual = (bool)target.GetProperty("IsOscillating");
Assert.AreEqual(expected, actual);
}
Notes:
- Because this is a state-related test, the
PrivateObject
class is used to gain access to the class' field. - The
SetProperty()
method is used to change the backing field value. The first argument indicates the identifier of the property that you want to access the backing field for, and the second argument is the value you want to change the backing field to.
It would not be the proper practice to do the following:
[TestMethod]
public void ToggleOscillation_TurnOffOscillation_UpdateState()
{
// Arrange
OscillatingFan fan = new OscillatingFan();
// This is not good
fan.ToggleOscillation();
// This is also not good
//fan.IsOscillating = false;
// Act
fan.ToggleOscillation();
// Assert
bool expected = false;
bool actual = (bool)target.GetProperty("IsOscillating");
Assert.AreEqual(expected, actual);
}
Notes:
- This test does not test the unit in isolation.