Есть несколько шагов, прежде чем мы достигнем того класса, который у вас сейчас есть.
Шаг 1
ServiceStation
тесно связан с ServiceStationUtility
.В результате мы не смогли выполнить юнит-тестирование ServiceStation
.
public class ServiceStation
{
ServiceStationUtility _gateUtility;
public ServiceStation()
{
this._gateUtility = new ServiceStationUtility();
}
public void OpenForService()
{
_gateUtility.OpenGate();
}
public void DoService()
{
}
public void CloseForDay()
{
_gateUtility.CloseGate();
}
}
Шаг 2
Мы внедряем зависимости через construction injection pattern
, и мы можем каким-то образом реализовать юнит-тесты, но ServiceStation
все еще тесно связан с ServiceStationUtility
.
public class ServiceStation
{
ServiceStationUtility _gateUtility;
public ServiceStation(ServiceStationUtility gateUtility)
{
this._gateUtility = gateUtility;
}
public void OpenForService()
{
_gateUtility.OpenGate();
}
public void DoService()
{
//Check if service station is opened and then
//complete the vehicle service
}
public void CloseForDay()
{
_gateUtility.CloseGate();
}
}
Шаг 3
Принцип замещения Лискова - Подкласс должен быть взаимозаменяемым с суперклассом.
Принцип обращения зависимостей - Компоненты высокого уровня не должны зависеть от компонентов низкого уровня или не должны нести ответственность за их создание.Вместо этого они должны зависеть от предоставленной им абстракции.
И наконец то, что у вас есть.Это в основном удовлетворяет принципам SO_ID;Принцип замены Лискова в этом случае не требуется.
public class ServiceStation
{
IGateUtility _gateUtility;
public ServiceStation(IGateUtility gateUtility)
{
this._gateUtility = gateUtility;
}
public void OpenForService()
{
_gateUtility.OpenGate();
}
public void DoService()
{
//Check if service station is opened and then
//complete the vehicle service
}
public void CloseForDay()
{
_gateUtility.CloseGate();
}
}
public interface IGateUtility
{
void OpenGate();
void CloseGate();
}
Образцы модульных тестов
Класс, который зависит от интерфейса, больше ни от чего не зависит.Эта абстракция обеспечивает слабую связь и позволяет легко выполнять юнит-тесты.
using Moq;
using Xunit;
public class ServiceStationTests
{
[Fact]
public void OpenForService_should_call_OpenGate_once()
{
// Arrange
var mockGateUtility = new Mock<IGateUtility>();
mockGateUtility.Setup(x => x.OpenGate());
// Act
var sut = new ServiceStation(mockGateUtility.Object);
sut.OpenForService();
// Assert
mockGateUtility.Verify(x => x.OpenGate(), Times.Once);
}
[Fact]
public void CloseForDay_should_call_CloseGate_once()
{
// Arrange
var mockGateUtility = new Mock<IGateUtility>();
mockGateUtility.Setup(x => x.CloseGate());
// Act
var sut = new ServiceStation(mockGateUtility.Object);
sut.CloseForDay();
// Assert
mockGateUtility.Verify(x => x.CloseGate(), Times.Once);
}
}