簡體   English   中英

遺留代碼以某種方式對ThreadAbortException作出反應的單元測試

[英]Unit test that legacy code reacts to ThreadAbortException in a certain way

我有一些遺留代碼,我想要進行測試。 這是必需品的復制品:

public class LegacyUnit
{
    private readonly ICollaborator collaborator;

    public LegacyUnit(ICollaborator collaborator) 
    {
        this.collaborator = collaborator;
    }

    public object GetStuff(HttpContextBase context, string input)
    {
        try 
        {
            if (input == "")
            {
                context.Response.End();
            }

            collaborator.DoOtherStuff();

            return "Done!";
        }
        catch (ThreadAbortException) 
        { }

        return null;
    }
}

現在,這個遺留單元存在一些問題,但是現在我只是試圖讓它受到考驗。 具體來說,我想測試一下,如果Response.End()引發一個ThreadAbort ,則不會調用該collaborator.DoOtherStuff

問題:你如何提出這樣的例外?

我已經閱讀了這個問題及其在ThreadAbortException答案 ,並了解它是特殊的。 但是,我從這些帖子中看不到如何在單元測試中處理這個問題。

這是我的嘗試:

[Test]
public void DoesNotCallCollaboratorOnThreadAbort()
{
    var testResponseMock = new Mock<HttpResponseBase>();
    var testContextMock = new Mock<HttpContextBase>();
    var collaboratorMock = new Mock<ICollaborator>();

    testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
    testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error

    var unit = new LegacyUnit(collaboratorMock.Object);
    unit.GetStuff(testContextMock.Object, "");

    collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
}

顯然編譯器抱怨: ThreadAbortException沒有可用的構造函數。 此外,它是sealed (可能有充分的理由),因此創建一個“可測試的”子類是行不通的。

獲得此類代碼的正確方法是什么? 它甚至是可行的,還是LegacyUnit對測試不友好?


完整,最小的repro(帶有NUnit 2.6.4和Moq 4.5.9的空.NET 4.5類庫):

public interface ICollaborator
{
    void DoOtherStuff();
}

public class LegacyUnit
{
    private readonly ICollaborator collaborator;

    public LegacyUnit(ICollaborator collaborator)
    {
        this.collaborator = collaborator;
    }

    public object GetStuff(HttpContextBase context, string input)
    {
        try
        {
            if (input == "") context.Response.End();
            collaborator.DoOtherStuff();
            return "Done!";
        }
        catch (ThreadAbortException)
        { }

        return null;
    }
}

[TestFixture]
public class LegacyUnitTests
{
    [Test]
    public void DoesNotCallCollaboratorOnThreadAbort()
    {
        var testResponseMock = new Mock<HttpResponseBase>();
        var testContextMock = new Mock<HttpContextBase>();
        var collaboratorMock = new Mock<ICollaborator>();

        testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
        testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error here

        var unit = new LegacyUnit(collaboratorMock.Object);
        unit.GetStuff(testContextMock.Object, "");

        collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
    }
}

通過在其上調用Abort在目標線程中引發ThreadAbortException 您可以創建一個線程來運行測試,並在模擬testResponseMock.End調用Abort ,例如

testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);

var unit = new LegacyUnit(collaboratorMock.Object);
var thread = new Thread(() => unit.GetStuff(testContextMock.Object, ""));

testResponseMock.Setup(x => x.End()).Callback(() => { Thread.CurrentThread.Abort(); });

thread.Start();
thread.Join();

collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM