DÜZENLEME : Adedi 4.10'da artık bir out veya ref parametresi olan bir temsilciyi doğrudan Geri Arama işlevine iletebilirsiniz:
mock
.Setup(x=>x.Method(out d))
.Callback(myDelegate)
.Returns(...);
Bir temsilci tanımlamanız ve başlatmanız gerekir:
...
.Callback(new MyDelegate((out decimal v)=>v=12m))
...
4.10'dan önceki Adedi sürümü için:
Avner Kashtan, blogunda out parametresini geri aramadan ayarlamaya izin veren bir uzantı yöntemi sunuyor: aramadan Adedi, Geri Aramalar ve Out parametreleri: özellikle zor bir durum
Çözüm hem zarif hem de hacky. Zarif, diğer Moq geri aramalarıyla evde hissedilen akıcı bir sözdizimi sağlar. Ve hacky çünkü bazı dahili Moq API'lerini yansıma yoluyla çağırmaya dayanır.
Yukarıdaki bağlantıda sağlanan uzantı yöntemi benim için derlenmedi, bu yüzden aşağıda düzenlenmiş bir sürüm sağladım. Sahip olduğunuz her sayıda giriş parametresi için bir imza oluşturmanız gerekir; 0 ve 1 sağladım, ancak daha da genişletmek basit olmalı:
public static class MoqExtensions
{
public delegate void OutAction<TOut>(out TOut outVal);
public delegate void OutAction<in T1,TOut>(T1 arg1, out TOut outVal);
public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, TOut>(this ICallback<TMock, TReturn> mock, OutAction<TOut> action)
where TMock : class
{
return OutCallbackInternal(mock, action);
}
public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, T1, TOut>(this ICallback<TMock, TReturn> mock, OutAction<T1, TOut> action)
where TMock : class
{
return OutCallbackInternal(mock, action);
}
private static IReturnsThrows<TMock, TReturn> OutCallbackInternal<TMock, TReturn>(ICallback<TMock, TReturn> mock, object action)
where TMock : class
{
mock.GetType()
.Assembly.GetType("Moq.MethodCall")
.InvokeMember("SetCallbackWithArguments", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock,
new[] { action });
return mock as IReturnsThrows<TMock, TReturn>;
}
}
Yukarıdaki uzantı yöntemiyle, aşağıdaki gibi çıkış parametreleriyle bir arabirimi test edebilirsiniz:
public interface IParser
{
bool TryParse(string token, out int value);
}
.. aşağıdaki Adedi kurulumu ile:
[TestMethod]
public void ParserTest()
{
Mock<IParser> parserMock = new Mock<IParser>();
int outVal;
parserMock
.Setup(p => p.TryParse("6", out outVal))
.OutCallback((string t, out int v) => v = 6)
.Returns(true);
int actualValue;
bool ret = parserMock.Object.TryParse("6", out actualValue);
Assert.IsTrue(ret);
Assert.AreEqual(6, actualValue);
}
Düzenleme : Geçersiz dönüş yöntemlerini desteklemek için sadece yeni aşırı yükleme yöntemleri eklemeniz gerekir:
public static ICallbackResult OutCallback<TOut>(this ICallback mock, OutAction<TOut> action)
{
return OutCallbackInternal(mock, action);
}
public static ICallbackResult OutCallback<T1, TOut>(this ICallback mock, OutAction<T1, TOut> action)
{
return OutCallbackInternal(mock, action);
}
private static ICallbackResult OutCallbackInternal(ICallback mock, object action)
{
mock.GetType().Assembly.GetType("Moq.MethodCall")
.InvokeMember("SetCallbackWithArguments", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock, new[] { action });
return (ICallbackResult)mock;
}
Bu, aşağıdakiler gibi arayüzleri test etmeye izin verir:
public interface IValidationRule
{
void Validate(string input, out string message);
}
[TestMethod]
public void ValidatorTest()
{
Mock<IValidationRule> validatorMock = new Mock<IValidationRule>();
string outMessage;
validatorMock
.Setup(v => v.Validate("input", out outMessage))
.OutCallback((string i, out string m) => m = "success");
string actualMessage;
validatorMock.Object.Validate("input", out actualMessage);
Assert.AreEqual("success", actualMessage);
}
It.IsAny<T>()
benzeri eşleştirici (ref It.Ref<T>.IsAny
kurma) desteğe.Callback()
ve.Returns()
usul şekline uyan özel bir temsilci tipleri yoluyla. Korumalı yöntemler eşit şekilde desteklenir. Bkz . Aşağıdaki cevabım .