【发布时间】:2014-09-07 01:09:10
【问题描述】:
想象下面这个人为的例子:
public class LoginController {
private readonly IValidate _validator;
private readonly IAuthenticate _authenticator;
public LoginController(IValidate validator, IAuthenticate authenticator) {
_validator = validator;
_authenticator = authenticator;
}
public HttpStatusCode Login(LoginRequest request) {
if (!_validator.IsValid(request)) {
return HttpStatusCode.BadRequest;
}
if (!_authenticator.IsAuthenticated(request.Email, request.Password)) {
return HttpStatusCode.Unauthorized;
}
return HttpStatusCode.OK;
}
}
public class LoginRequest {
public string Email {get; set;}
public string Password {get; set;}
}
public interface IValidate {
bool IsValid(LoginRequest request);
}
public interface IAuthenticate {
bool IsAuthenticated(string email, string password);
}
通常我会编写如下测试:
[TestFixture]
public class InvalidRequest
{
private LoginRequest _invalidRequest;
private IValidate _validator;
private HttpStatusCode _response;
void GivenARequest()
{
_invalidRequest = new LoginRequest();
}
void AndGivenThatRequestIsInvalid() {
_validator = Substitute.For<IValidate>();
_validator.IsValid(_invalidRequest).Returns(false);
}
void WhenAttemptingLogin()
{
_response = new LoginController(_validator, null)
.Login(_invalidRequest);
}
void ThenShouldRespondWithBadRequest()
{
Assert.AreEqual(HttpStatusCode.BadRequest, _response);
}
[Test]
public void Execute()
{
this.BDDfy();
}
}
public class LoginUnsuccessful
{
private LoginRequest _request;
private IValidate _validator;
private IAuthenticate _authenticate;
private HttpStatusCode _response;
void GivenARequest()
{
_request = new LoginRequest();
}
void AndGivenThatRequestIsValid() {
_validator = Substitute.For<IValidate>();
_validator.IsValid(_request).Returns(true);
}
void ButGivenTheLoginCredentialsDoNotExist() {
_authenticate = Substitute.For<IAuthenticate>();
_authenticate.IsAuthenticated(
_request.Email,
_request.Password
).Returns(false);
}
void WhenAttemptingLogin()
{
_response = new LoginController(_validator, _authenticate)
.Login(_request);
}
void ThenShouldRespondWithUnauthorized()
{
Assert.AreEqual(HttpStatusCode.Unauthorized, _response);
}
[Test]
public void Execute()
{
this.BDDfy();
}
}
但是,在观看了以下视频 Ian Cooper: TDD, where did it all go wrong 并进行了更多阅读之后,我开始认为我的测试与代码的实现联系得太紧密了。例如,我在第一个实例中尝试测试的行为是,如果我们尝试使用无效请求登录,我们会以错误请求的 http 状态代码响应。问题是我正在通过存根 IValidate 依赖项来测试它。如果实现者认为IValidate 抽象不再有用并决定在Login 方法中验证内联请求,那么系统的行为 没有改变,但是我的测试现在中断了。
但是,唯一的另一个替代方案是集成测试,我启动 Web 服务器并点击登录端点并断言响应。问题是这既脆弱又复杂,因为我们最终需要在第三方凭证存储中拥有一个有效用户来测试用户登录成功的场景。
所以我的问题是,我的理解是否不正确,或者在针对实现的测试和全面的集成测试之间是否存在中间立场?
【问题讨论】:
标签: unit-testing testing tdd bdd acceptance-testing