Я думал, что попробую кодовое ката, которое имитирует банкомат в командной строке.Я решил управлять дизайном, используя TDD.Я столкнулся с интересным сценарием, и мне любопытно, что другие сделали в этом сценарии.
Если вы посмотрите (внизу) на мой класс AtmMachine, вы заметите, что янамеренно выходить из цикла while, чтобы время моих тестов не истекло.Это похоже на запах кода для меня, и я хотел бы знать, если другие делают такие вещи.
Мои нынешние чувства разделились между:
- "Я делаю этонеправильно "при попытке выполнить модульное тестирование текущего выполнения
- Невозможность написать для него модульный тест подразумевает, что" while "является неправильной конструкцией
Вот мои тестына данный момент для банкомата:
[TestClass]
public class when_atm_starts
{
private static readonly string WELCOME_MSG = "Welcome to Al Banco de Ruiz!";
private AtmMachine _atm;
private Mock<IAtmInput> _inputMock;
private Mock<IAtmOutput> _outputMock;
private Mock<ILogger> _loggerMock;
private Mock<ICommandFactory> _cmdFactoryMock;
[TestInitialize]
public void BeforeEachTest()
{
_inputMock = new Mock<IAtmInput>();
_outputMock = new Mock<IAtmOutput>();
_loggerMock = new Mock<ILogger>();
_cmdFactoryMock = new Mock<ICommandFactory>();
_atm = new AtmMachine(_inputMock.Object, _outputMock.Object, _loggerMock.Object, _cmdFactoryMock.Object);
}
[TestMethod]
public void no_one_should_be_logged_in()
{
this.SetupForCancelledUser();
_atm.Start();
Assert.IsNull(_atm.CurrentUser);
}
[TestMethod]
public void should_print_welcome_to_output()
{
this.SetupForCancelledUser();
_atm.Start();
_outputMock.Verify(o => o.Write(WELCOME_MSG));
}
[TestMethod]
public void should_execute_login_command()
{
Mock<ILoginCommand> loginCmdMock = new Mock<ILoginCommand>();
_cmdFactoryMock.Setup(cf => cf.GetLoginCommand(_inputMock.Object, _outputMock.Object))
.Returns(loginCmdMock.Object);
loginCmdMock.Setup(lc => lc.LogonUser())
.Returns(AtmUser.CancelledUser);
_atm.Start();
loginCmdMock.Verify(lc => lc.LogonUser());
}
private void SetupForCancelledUser()
{
Mock<ILoginCommand> loginCmdMock = new Mock<ILoginCommand>();
_cmdFactoryMock.Setup(cf => cf.GetLoginCommand(_inputMock.Object, _outputMock.Object))
.Returns(loginCmdMock.Object);
loginCmdMock.Setup(lc => lc.LogonUser())
.Returns(AtmUser.CancelledUser);
}
}
А вот соответствующий класс AtmMachine.
public class AtmMachine
{
public static readonly string WELCOME_MSG = "Welcome to Al Banco de Ruiz!";
private bool _shouldContinue;
private ILogger _log;
private ICommandFactory _cmdFactory;
private IAtmInput _input;
private IAtmOutput _output;
public object CurrentUser { get; set; }
public AtmMachine(
IAtmInput input,
IAtmOutput output,
ILogger logger,
ICommandFactory cmdFactory)
{
this._input = input;
this._output = output;
this._log = logger;
this._cmdFactory = cmdFactory;
}
public void Start()
{
_shouldContinue = true;
while (_shouldContinue)
{
_output.Clear();
_output.Write(WELCOME_MSG);
AtmUser user = this.GetNextUser();
if (user == AtmUser.CancelledUser) { _shouldContinue = false; }
_shouldContinue = false;
}
}
private AtmUser GetNextUser()
{
ILoginCommand loginCmd = _cmdFactory.GetLoginCommand(_input, _output);
return loginCmd.LogonUser();
}
}