Tak, jest to możliwe, jeśli nie masz nic przeciwko skakaniu przez kilka mniejszych kółek. Zrobiłem to już wcześniej w przypadku jednego z moich projektów. Dobra, podstawowa technika. Właśnie testowałem go w Visual Studio 2008, a to działa:
var mockMessage1 = new Mock<IMessage>();
var mockMessage2 = new Mock<IMessage>();
var mockMessage3 = new Mock<IMessage>();
var messageQueue = new Queue<IMessage>(new [] { mockMessage1.Object, mockMessage2.Object, mockMessage3.Object });
var mockMsmqWrapper = new Mock<IMsmqWrapper>();
mockMsmqWrapper.Setup(x => x.GetMessage()).Returns(() => messageQueue.Dequeue()).Callback(() =>
{
if (messageQueue.Count == 0)
mockMsmqWrapper.Setup(x => x.GetMessage()).Throws<MyCustomException>();
});
Kilka uwag:
- Nie musiał wrócić szydzili wiadomości, ale jest to przydatne, jeśli chcesz zweryfikować oczekiwania na każdej wiadomości, aby sprawdzić, czy określone metody zostały wywołane lub czy zostały ustawione właściwości.
- Idea kolejki nie jest moją własnością, tylko wskazówka, którą otrzymałem od posta na blogu.
- Powodem, dla którego zgłaszam wyjątek MyCustomException jest to, że klasa Queue automatycznie zgłasza wyjątek InvalidOperationException. Chciałem się upewnić, że wyśmiewany obiekt MsmqWrapper zgłasza wyjątek z powodu Moq, a nie z powodu kończącej się kolejki elementów.
Oto pełny kod, który działa. Należy pamiętać, że ten kod jest brzydki, w niektórych miejscach, ale chciałem tylko pokazać, jak może to być testowane:
public interface IMsmqWrapper
{
IMessage GetMessage();
}
public class MsmqWrapper : IMsmqWrapper
{
public IMessage GetMessage()
{
throw new NotImplementedException();
}
}
public class Processor
{
private IMsmqWrapper _wrapper;
public int MessagesProcessed { get; set; }
public bool ExceptionThrown { get; set; }
public Processor(IMsmqWrapper msmqWrapper)
{
_wrapper = msmqWrapper;
}
public virtual void ProcessMessages()
{
_wrapper.GetMessage();
MessagesProcessed++;
_wrapper.GetMessage();
MessagesProcessed++;
_wrapper.GetMessage();
MessagesProcessed++;
try
{
_wrapper.GetMessage();
}
catch (MyCustomException)
{
ExceptionThrown = true;
}
}
}
[Test]
public void TestMessageQueueGetsExhausted()
{
var mockMessage1 = new Mock<IMessage>();
var mockMessage2 = new Mock<IMessage>();
var mockMessage3 = new Mock<IMessage>();
var messageQueue = new Queue<IMessage>(new [] { mockMessage1.Object, mockMessage2.Object, mockMessage3.Object });
var mockMsmqWrapper = new Mock<IMsmqWrapper>();
mockMsmqWrapper.Setup(x => x.GetMessage()).Returns(() => messageQueue.Dequeue()).Callback(() =>
{
if (messageQueue.Count == 0)
mockMsmqWrapper.Setup(x => x.GetMessage()).Throws<InvalidProgramException>();
});
var processor = new Processor(mockMsmqWrapper.Object);
processor.ProcessMessages();
Assert.That(processor.MessagesProcessed, Is.EqualTo(3));
Assert.That(processor.ExceptionThrown, Is.EqualTo(true));
}
+1 Ponieważ Moq jest super ;-) – toxvaerd
Opowiedz mi o tym! Przez ponad rok używałem jakiegoś komercyjnego produktu, którego nazwa pozostanie tu niewidoczna, a NIENAWIDZIAŁam z drwin. Musiałem ciągle czytać i ponownie czytać dokumentację za każdym razem. Moq to taki powiew świeżego powietrza. Udało mi się go użyć za kilka minut i rzadko muszę czytać dokumentację. –
Używam RhinoMocks, ale myślałem, że dam Moqowi szansę, aby zobaczyć, jak to się porównuje i rozpowszechniać moją wiedzę. Jestem teraz konwerterem - uważam, że składnia Moq jest łatwiejsza do odczytania podczas skanowania kodu. – BlackWasp