簡體   English   中英

我將如何對void方法進行單元測試?

[英]How would I be able to unit test a void method?

我想測試檢查車輛運動方向的方法。 這是一個空方法,具有一個參數-整數。

據我所知,所有的if都應該分為不同的測試方法,但是我不知道該怎么做。

/// <summary>
        /// checks the east neighbour of the crossing on a given cell
        /// </summary>
        /// <param name="cellNr">the cell Nr of the crossing whose neighbour ///its checked</param>

    public void CheckEast(int cellNr)
    {
        Crossing cr = Cells[cellNr].Crossing;

        //If there is east neighbour - laneIns of the current crossing with direction east are NOT endLane
        if (cells[cellNr + 1].Taken)
        {
            foreach (LaneIn laneIn in cr.LaneInList)
            {
                if (laneIn.Direction == "west")
                {
                    laneIn.EndLane = false;
                }
            }

            //car should NOT be spawned from east && LaneOut of current crossing with direction east is NOT endLane
            cr.IncomingStreams[3] = "";
            cr.LaneOutList[0].EndLane = false;

            //LaneIn 'east' of the east neighbour is NOT endLane
            foreach (LaneIn laneIn in cells[cellNr + 1].Crossing.LaneInList)
            {
                if (laneIn.Direction == "east")
                {
                    laneIn.EndLane = false;
                }
            }
            //no spawned car in the neighbour from the east laneIns and LaneOut 'west' is not endlane
            cells[cellNr + 1].Crossing.IncomingStreams[1] = "";
            cells[cellNr + 1].Crossing.LaneOutList[1].EndLane = false;
            cr.Neighbours[1] = cells[cellNr + 1].Crossing;
            cells[cellNr + 1].Crossing.Neighbours[3] = cr;
        }
        //if there is NO neighbour on east side, laneIns of the current crossing are endlane(spawning point)
        //laneout is endlane, cars are erased after leaving it
        else
        {
            cr.Neighbours[1] = null;
            cr.IncomingStreams[3] = "west";
            cr.LaneOutList[0].EndLane = true;
            foreach (LaneIn laneIn in cr.LaneInList)
            {
                if (laneIn.Direction == "west")
                {
                    laneIn.EndLane = true;
                }
            }
        }
    }

要從字面上回答您的問題,如果一個方法沒有返回值,那么它還必須產生其他副作用。 (如果它不返回任何東西或沒有副作用,那么它什么也不做。)

如果method更改了類本身的狀態,則可以執行該方法並聲明所需的狀態:

public class Counter
{
    public int Value { get; private set; }

    public void Increment() => Value++;
}
public void Counter_increments()
{
    var subject = new Counter();
    subject.Increment();
    Assert.AreEqual(1, subject.Value());
}

也許您要測試的行為是類與某些依賴項之間的交互。 有幾種方法可以做到這一點。 一種是檢查依賴項的狀態:

public class ClassThatIncrementsCounter
{
    public readonly Counter _counter;

    public ClassThatIncrementsCounter(Counter counter)
    {
        _counter = counter;
    }

    public void DoSomething()
    {
        // does something and then increments the counter
        _counter.Increment();
    }
}

[TestMethod]
public void DoSomething_increments_counter()
{
    var counter = new Counter();
    var subject = new ClassThatIncrementsCounter(counter);
    subject.DoSomething();
    Assert.AreEqual(1, counter.Value);
}

您還可以使用Moq之類的庫來驗證您的類是否與依賴項進行了交互:

public class ClassThatIncrementsCounter
{
    public readonly ICounter _counter;

    public ClassThatIncrementsCounter(ICounter counter)
    {
        _counter = counter;
    }

    public void DoSomething()
    {
        // does something and then increments the counter
        _counter.Increment();
    }
}

[TestMethod]
public void DoSomething_increments_counter()
{
    var counter = new Mock<ICounter>();

    // indicate that we want to track whether this method was called.
    counter.Setup(x => x.Increment()).Verifiable();
    var subject = new ClassThatIncrementsCounter(counter.Object);
    subject.DoSomething();

    // verify that the method was called.
    counter.Verify(x => x.Increment());
}

如前所述,為了使此方法正常工作,有必要將方法分解為較小的塊,以便我們可以單獨進行測試。 如果一個方法做出了很多決定,那么為了進行全面測試,我們需要針對每種適用的組合或代碼可以執行的每個可能的分支進行測試。 這就是為什么具有很多條件的方法更難測試的原因。

我花了一些時間查看您的代碼,但是還不清楚它實際上在做什么,以至於很難建議如何重構它。

您可以采用更大的代碼塊,像這樣重復執行:

        foreach (LaneIn laneIn in cr.LaneInList)
        {
            if (laneIn.Direction == "west")
            {
                laneIn.EndLane = false;
            }
        }

        foreach (LaneIn laneIn in cr.LaneInList)
        {
            if (laneIn.Direction == "west")
            {
                laneIn.EndLane = true;
            }
        }

...並用類似的方法替換它們,但您要給它們取清晰,有意義的名稱。 我不能這樣做,因為我不確定他們做什么:

public void SetEndLaneInDirection(List<LaneIn> laneInList, string direction, bool isEnd)
{
    foreach (LaneIn laneIn in laneInList)
    {
        if (laneIn.Direction == direction)
        {
            laneIn.EndLane = isEnd;
        }
    }
}

現在,一小段代碼更易於測試。 或者,如果您有全部都進行如下相關更新的方法塊:

        cells[cellNr + 1].Crossing.IncomingStreams[1] = "";
        cells[cellNr + 1].Crossing.LaneOutList[1].EndLane = false;
        cr.Neighbours[1] = cells[cellNr + 1].Crossing;
        cells[cellNr + 1].Crossing.Neighbours[3] = cr;

然后將它們放在方法中,並再次給它起一個清晰的名稱。

現在,您可以設置類,調用方法並聲明您期望的狀態。

副作用是,當您用命名良好的方法調用替換代碼塊時,您的代碼將變得更易於閱讀,因為該方法調用以近似英語的形式說明了每個步驟的操作。

事后要做起來要困難得多。 挑戰的一部分是學習編寫易於測試的代碼。 好消息是,隨着我們這樣做,我們的代碼自然會變得更加簡單和易於遵循。 而且我們有測試。

這是一篇有關如何重構現有代碼以使其更易於測試的出色文章

在你的單元測試,你叫CheckEastcellNr設置為某個值,然后斷言預期的副作用(即,改變)是在制造CellsLaneInList等,數據結構。

暫無
暫無

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

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