最小起订量和多种方法设置
Moq and multiple method setup
我正在尝试同时使用 xUnit 学习最小起订量和单元测试。
我有一个身份验证逻辑 class,其中包含一些方法。它们都使用 AuthenticationDataAccessor。我正在尝试模拟该访问器以仅保留与逻辑的单元测试隔离。
我正在尝试在我的逻辑中对两种方法的逻辑进行单元测试 class。
RegisterAsync 和 AuthenticateAsync
private void SetupMocks()
{
// Mock the data accessor.
var _mockedDataAccessor = new Mock<IAuthenticationData>();
// Moke the call that will go to the mocked data accessor.
var _mockedAuthenticationRequest = new AuthenticationRequest { Username = It.IsAny<string>(), Password = It.IsAny<string>() };
var _mockedRegistrationRequest = new RegistrationRequest { Email = It.IsAny<string>(), Password = It.IsAny<string>(), Firstname = It.IsAny<string>(), Surname = It.IsAny<string>() };
// Setup the accessor.
_mockedDataAccessor
.Setup(x => x
.AuthenticateAsync(_mockedAuthenticationRequest))
.ReturnsAsync(
new SharedLib.Responses.UserResponse
{
ResponseState = new SharedLib.Responses.ResponseState
{
Description = "Moq description",
IsSuccess = true,
ResponseCode = ResponseCode.OK,
SystemError = false
}
});
_mockedDataAccessor
.Setup(x => x
.RegisterAsync(_mockedRegistrationRequest))
.ReturnsAsync(
new SharedLib.Responses.RegistrationResponse
{
ResponseState = new SharedLib.Responses.ResponseState
{
Description = "Moq description",
IsSuccess = true,
ResponseCode = ResponseCode.OK,
SystemError = false
}
});
// Create the logic reference based on the mocked data accessor
_logic = new AuthenticationLogic(_mockedDataAccessor.Object);
}
所以,我有两个设置电话。一种用于我正在模拟的数据访问器方法。
但是,当我执行单元测试时:
[Fact]
public async void RegisterWithValidDetailsReturnsSuccess()
{
SetupMocks();
var result = await _logic.RegisterAsync(new RegistrationRequest
{
Email = "a.valid@email.com",
Firstname = "ValidFirstname",
Password = "AString@Password123",
Surname = "AValid Surname",
TimezoneId = 1
});
Assert.Equal(ResponseCode.OK, result.ResponseState.ResponseCode);
}
result
始终为空。我希望它是我在上面的设置中设置的。
请注意,使用我的 Authenticate 模拟的测试有效。看来第二次模拟失败了。
[Fact]
public async void BlankUsernameReturnsError()
{
SetupMocks();
var result = await _logic.AuthenticateAsync(new AuthenticationRequest
{
Password = "AFantastic123Password@",
Username = "",
});
Assert.Equal(ResponseCode.LoginInvalidCredentials, result.ResponseState.ResponseCode);
}
行得通。
也许你不能在同一个模拟 class 上有两个 'setup'?我需要为每个测试进行特定设置吗?也许 private void Setup()
是一个 problem/bad 想法?
你遇到的基本问题是:
_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(_mockedAuthenticationRequest))
.ReturnsAsync(...));
...告诉 Moq 在 AuthenticateAsync()
传递给确切参数 时以某种方式表现。由于这不是您的测试通过的内容,因此请从包罗万象的场景开始:
_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(It.IsAny<AuthenticationRequest>()))
.ReturnsAsync(...));
然后,如果需要,您可以缩小要求,具体取决于您的测试要达到的目标;例如当用户名是 "Alice" 时,你可以 return 一个值,当它是 "Bob":
时,你可以 return 一个值
_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(It.Is<AuthenticationRequest>(a => a.Username == "Alice")))
.ReturnsAsync(...one value...));
_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(It.Is<AuthenticationRequest>(a => a.Username == "Bob")))
.ReturnsAsync(...something else...));
我正在尝试同时使用 xUnit 学习最小起订量和单元测试。
我有一个身份验证逻辑 class,其中包含一些方法。它们都使用 AuthenticationDataAccessor。我正在尝试模拟该访问器以仅保留与逻辑的单元测试隔离。
我正在尝试在我的逻辑中对两种方法的逻辑进行单元测试 class。
RegisterAsync 和 AuthenticateAsync
private void SetupMocks()
{
// Mock the data accessor.
var _mockedDataAccessor = new Mock<IAuthenticationData>();
// Moke the call that will go to the mocked data accessor.
var _mockedAuthenticationRequest = new AuthenticationRequest { Username = It.IsAny<string>(), Password = It.IsAny<string>() };
var _mockedRegistrationRequest = new RegistrationRequest { Email = It.IsAny<string>(), Password = It.IsAny<string>(), Firstname = It.IsAny<string>(), Surname = It.IsAny<string>() };
// Setup the accessor.
_mockedDataAccessor
.Setup(x => x
.AuthenticateAsync(_mockedAuthenticationRequest))
.ReturnsAsync(
new SharedLib.Responses.UserResponse
{
ResponseState = new SharedLib.Responses.ResponseState
{
Description = "Moq description",
IsSuccess = true,
ResponseCode = ResponseCode.OK,
SystemError = false
}
});
_mockedDataAccessor
.Setup(x => x
.RegisterAsync(_mockedRegistrationRequest))
.ReturnsAsync(
new SharedLib.Responses.RegistrationResponse
{
ResponseState = new SharedLib.Responses.ResponseState
{
Description = "Moq description",
IsSuccess = true,
ResponseCode = ResponseCode.OK,
SystemError = false
}
});
// Create the logic reference based on the mocked data accessor
_logic = new AuthenticationLogic(_mockedDataAccessor.Object);
}
所以,我有两个设置电话。一种用于我正在模拟的数据访问器方法。
但是,当我执行单元测试时:
[Fact]
public async void RegisterWithValidDetailsReturnsSuccess()
{
SetupMocks();
var result = await _logic.RegisterAsync(new RegistrationRequest
{
Email = "a.valid@email.com",
Firstname = "ValidFirstname",
Password = "AString@Password123",
Surname = "AValid Surname",
TimezoneId = 1
});
Assert.Equal(ResponseCode.OK, result.ResponseState.ResponseCode);
}
result
始终为空。我希望它是我在上面的设置中设置的。
请注意,使用我的 Authenticate 模拟的测试有效。看来第二次模拟失败了。
[Fact]
public async void BlankUsernameReturnsError()
{
SetupMocks();
var result = await _logic.AuthenticateAsync(new AuthenticationRequest
{
Password = "AFantastic123Password@",
Username = "",
});
Assert.Equal(ResponseCode.LoginInvalidCredentials, result.ResponseState.ResponseCode);
}
行得通。
也许你不能在同一个模拟 class 上有两个 'setup'?我需要为每个测试进行特定设置吗?也许 private void Setup()
是一个 problem/bad 想法?
你遇到的基本问题是:
_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(_mockedAuthenticationRequest))
.ReturnsAsync(...));
...告诉 Moq 在 AuthenticateAsync()
传递给确切参数 时以某种方式表现。由于这不是您的测试通过的内容,因此请从包罗万象的场景开始:
_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(It.IsAny<AuthenticationRequest>()))
.ReturnsAsync(...));
然后,如果需要,您可以缩小要求,具体取决于您的测试要达到的目标;例如当用户名是 "Alice" 时,你可以 return 一个值,当它是 "Bob":
时,你可以 return 一个值_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(It.Is<AuthenticationRequest>(a => a.Username == "Alice")))
.ReturnsAsync(...one value...));
_mockedDataAccessor
.Setup(x => x.AuthenticateAsync(It.Is<AuthenticationRequest>(a => a.Username == "Bob")))
.ReturnsAsync(...something else...));