C#에서 Moq를 사용하여 목에 전달된 개체를 확인하는 3가지 방법
일부 개발자는 모의 사용을 엄격하게 반대하지만 특히 모의 작업이 값을 반환하지 않지만 여전히 올바른 값으로 특정 메서드를 호출했는지 확인하려는 경우 유용할 수 있습니다.
이 기사에서는 C# 단위 테스트에서 Moq를 사용할 때 목에 전달된 값을 확인하는 3가지 방법을 배웁니다.
이 세 가지 방법을 더 잘 설명하기 위해 다음과 같은 방법을 만들었습니다.
public void UpdateUser(User user, Preference preference)
{
var userDto = new UserDto
{
Id = user.id,
UserName = user.username,
LikesBeer = preference.likesBeer,
LikesCoke = preference.likesCoke,
LikesPizza = preference.likesPizza,
};
_userRepository.Update(userDto);
}
UpdateUser
는 단순히 user
와 preference
의 두 개체를 받아들여 하나의 UserDto
개체로 결합한 다음 클래스 생성자에 주입된 인터페이스인 Update
의 _userRepository
메서드를 호출합니다.보시다시피
_userRepository.Update
의 반환 값에는 관심이 없습니다. 오히려 올바른 값으로 호출하고 있는지 확인하는 데 관심이 있습니다.우리는 3가지 방법으로 그것을 할 수 있습니다.
It.Is로 각 속성을 확인합니다.
가장 간단하고 가장 일반적인 방법은
It.Is<T>
메서드 내에서 Verify
를 사용하는 것입니다.[Test]
public void VerifyEachProperty()
{
// Arrange
var user = new User(1, "Davide");
var preferences = new Preference(true, true, false);
UserDto expected = new UserDto
{
Id = 1,
UserName = "Davide",
LikesBeer = true,
LikesCoke = false,
LikesPizza = true,
};
//Act
userUpdater.UpdateUser(user, preferences);
//Assert
userRepo.Verify(_ => _.Update(It.Is<UserDto>(u =>
u.Id == expected.Id
&& u.UserName == expected.UserName
&& u.LikesPizza == expected.LikesPizza
&& u.LikesBeer == expected.LikesBeer
&& u.LikesCoke == expected.LikesCoke
)));
}
위의 예에서
It.Is<UserDto>
의 Update
메서드에 전달된 정확한 항목을 확인하기 위해 userRepo
를 사용했습니다.매개변수를 허용한다는 점에 유의하십시오. 해당 매개변수는
Func<UserDto, bool>
유형이며 이를 사용하여 기대치를 충족하는 시기를 정의할 수 있습니다.이 특별한 경우에는 해당 함수 내의 모든 속성을 확인했습니다.
u =>
u.Id == expected.Id
&& u.UserName == expected.UserName
&& u.LikesPizza == expected.LikesPizza
&& u.LikesBeer == expected.LikesBeer
&& u.LikesCoke == expected.LikesCoke
이 접근 방식은 몇 개의 필드에 대해서만 검사를 수행해야 할 때 잘 작동합니다. 그러나 더 많은 필드를 추가할수록 코드가 더 길고 복잡해집니다.
또한 이 접근 방식의 문제점은 실패할 경우 예상과 일치하지 않는 특정 필드에 대한 표시가 없기 때문에 실패의 원인이 무엇인지 이해하기 어려워진다는 것입니다.
다음은 오류 메시지의 예입니다.
Expected invocation on the mock at least once, but was never performed: _ => _.Update(It.Is<UserDto>(u => (((u.Id == 1 && u.UserName == "Davidde") && u.LikesPizza == True) && u.LikesBeer == True) && u.LikesCoke == False))
Performed invocations:
Mock<IUserRepository:1> (_):
IUserRepository.Update(UserDto { UserName = Davide, Id = 1, LikesPizza = True, LikesCoke = False, LikesBeer = True })
오류를 발견할 수 있습니까? 그리고 5개가 아닌 15개의 필드를 확인한다면 어떨까요?
외부 기능으로 확인
또 다른 접근 방식은 함수를 외부화하는 것입니다.
[Test]
public void WithExternalFunction()
{
//Arrange
var user = new User(1, "Davide");
var preferences = new Preference(true, true, false);
UserDto expected = new UserDto
{
Id = 1,
UserName = "Davide",
LikesBeer = true,
LikesCoke = false,
LikesPizza = true,
};
//Act
userUpdater.UpdateUser(user, preferences);
//Assert
userRepo.Verify(_ => _.Update(It.Is<UserDto>(u => AreEqual(u, expected))));
}
private bool AreEqual(UserDto u, UserDto expected)
{
Assert.AreEqual(expected.UserName, u.UserName);
Assert.AreEqual(expected.Id, u.Id);
Assert.AreEqual(expected.LikesBeer, u.LikesBeer);
Assert.AreEqual(expected.LikesCoke, u.LikesCoke);
Assert.AreEqual(expected.LikesPizza, u.LikesPizza);
return true;
}
여기서는
It.Is<T>
메서드에 외부 함수를 전달합니다.이 접근 방식을 통해 보다 명시적이고 포괄적인 검사를 정의할 수 있습니다.
그것의 좋은 부분은 어설션을 더 잘 제어할 수 있고 테스트가 실패할 경우 더 나은 오류 메시지가 표시된다는 것입니다.
Expected string length 6 but was 7. Strings differ at index 5.
Expected: "Davide"
But was: "Davidde"
나쁜 부분은 테스트 클래스를 다양한 메서드로 채우고 클래스를 쉽게 유지 관리하기 어렵게 만들 수 있다는 것입니다. 불행하게도 우리는 로컬 함수를 사용할 수 없습니다.
반면에 외부 기능을 사용하면 여러 테스트 사례에서 재사용할 수 있는 일부 테스트를 수행해야 할 때 외부 기능을 결합할 수 있습니다.
콜백으로 함수 매개변수 가로채기
마지막으로 Moq의 숨겨진 보석인 콜백을 사용할 수 있습니다.
콜백을 사용하면 메서드에서 호출한 항목에 대한 참조를 지역 변수에 저장할 수 있습니다.
[Test]
public void CompareWithCallback()
{
// Arrange
var user = new User(1, "Davide");
var preferences = new Preference(true, true, false);
UserDto actual = null;
userRepo.Setup(_ => _.Update(It.IsAny<UserDto>()))
.Callback(new InvocationAction(i => actual = (UserDto)i.Arguments[0]));
UserDto expected = new UserDto
{
Id = 1,
UserName = "Davide",
LikesBeer = true,
LikesCoke = false,
LikesPizza = true,
};
//Act
userUpdater.UpdateUser(user, preferences);
//Assert
userRepo.Verify(_ => _.Update(expected));
}
이러한 방식으로 로컬에서 사용하고
Verify
메서드에 의존하지 않고 해당 개체에 직접 어설션을 실행할 수 있습니다.또는 레코드를 사용하는 경우 이전 예제에서 수행한 것처럼 자동 동등성 검사를 사용하여
Verify
방법을 단순화할 수 있습니다.마무리
이 기사에서는 Moq로 조롱된 종속성에 전달된 객체에 대한 검사를 수행하는 3가지 방법을 살펴보았습니다.
각각의 방법에는 장단점이 있으며 가장 적합한 접근 방식을 선택하는 것은 귀하에게 달려 있습니다.
전달된 값에 대해 더 나은 검사를 수행할 수 있으므로 개인적으로 두 번째 및 세 번째 접근 방식을 선호합니다.
당신은 어때요?
지금은 즐거운 코딩하세요!
🐧
Reference
이 문제에 관하여(C#에서 Moq를 사용하여 목에 전달된 개체를 확인하는 3가지 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/bellonedavide/3-ways-to-check-the-object-passed-to-mocks-with-moq-in-c-5530텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)