Domanda

Al momento sto cercando di implementare una classe StopWatch. L'interfaccia è qualcosa di simile:

interface IStopWatch {
    void Run();
    void Stop();
    int SecondsElapsed { get; }
    int MinutesElapsed { get; }
}

In pratica la mia app sarà necessario utilizzare un StopWatch, ma per scopi di test che sarebbe stato bello avere un modo di modifing artifially risultati a StopWatches', in modo tale che è il motivo che sto facendo tutto il mio codice di riferimento di un posto di IStopWatch System.Stopwatch di .NET.

Come sto cercando di sviluppare questo test-First, dovrò rendere il codice per la mia classe StopWatch solo dopo aver scritto i suoi test. Ho già capito che i test ho intenzione di fare non stanno andando per essere unità di test, come io sto usando classe System.Stopwatch di .NET internamente.

Quindi, a mio undertanding, l'unica cosa che posso fare ora sono test che simile al seguente:

[TestMethod]
public void Right_After_Calling_Run_Elapsed_Minutes_Equals_Zero() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Assert.AreEqual<int>(0, stopWatch.ElapsedMinutes);
}

[TestMethod]
public void One_Second_After_Run_Elapsed_Seconds_Equals_One() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Thread.Sleep(1000 + 10);
    Assert.AreEqual<int>(1, stopWatch.ElapsedSeconds);
}

[TestMethod]
public void Sixty_Seconds_After_Run_Elapsed_Minutes_Equals_One() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Thread.Sleep(60 * 1000 + 1000);
    Assert.AreEqual<int>(1, stopWatch.ElapsedMinutes);            
}

Lo so non posso eseguire questo tutte le volte che le mie unità di test, ma penso che non c'è niente che io possa fare questo. È il mio approccio corretto o mi sto perdendo qualcosa?

Grazie

Modifica

Così ho finito dopo due consigli Quinn351 e Sjoerd di e codificato qualcosa che utilizza DateTimes invece di classe cronometro di NET:

public class MyStopWatch : IMyStopWatch {
    private DateTime? firstDateTime = null;
    private DateTime? secondDateTime = null;
    private bool isRunning = false;

    public void Start() {
        isRunning = true;
        firstDateTime = DateTime.Now;
    }

    public void Stop() {
        isRunning = false;
        secondDateTime = DateTime.Now;
    }

    public void Reset() {
        firstDateTime = null;
        secondDateTime = null;
        isRunning = false;
    }

    public TimeSpan GetTimeElapsed() {
        return secondDateTime.Value.Subtract(firstDateTime.Value);
    }
}

Questo mi permette di fare altre implementazioni che hanno getter / setter per entrambe le date in modo da poter fare GetTimeElapsed () ritorno quello che voglio.

È stato utile?

Soluzione

La classe cronometro probabilmente ottiene la data e l'ora da qualche parte. Fare un oggetto che restituisce la data corrente. Questo sarebbe una classe molto semplice. Durante il test, passare in un finto oggetto invece, che restituisce una data e un'ora falso. In questo modo, si può fingere il test come se molti secondi sono trascorsi.

class DateTime {
    public Date getDate() {
        return System.DateTime.Now();
    }
}

class MockDateTime {
    public Date getDate() {
        return this.fakeDate;
    }
}

class StopwatchTest {
    public void GoneInSixtySeconds() {
        MockDateTime d = new MockDateTime();
        d.fakeDate = '2010-01-01 12:00:00';
        Stopwatch s = new Stopwatch();
        s.Run();
        d.fakeDate = '2010-01-01 12:01:00';
        s.Stop();
        assertEquals(60, s.ElapsedSeconds);
    }
}

Altri suggerimenti

Perché "artifially modifing RISULTATI cronometri" ?! Qual è lo scopo di testare se la vostra intenzione di modificare i vostri risultati?

Per quanto riguarda il test si dovrebbe anche verificare il metodo di arresto e si dovrebbe verificare se la quantità di secondi è di circa 60 volte più che la quantità di minuti.

La classe che si sta scrivendo potrebbe anche usare StopWatch internamente e quindi modificare i risultati come richiesto (allora si può sempre tornare ai risultati originali).

PS:. I nomi di metodo dovrebbe essere più breve e non hanno sottolineature

Un problema è che cronometro non è precisa su processori con velocità di clock variabili ovvero quelle più attuali, come si può vedere con il seguente discussione

C # Cronometro mostra ora non corretta

Quindi, utilizzando Thread.Sleep wont darvi un tempo preciso. Si sarebbe meglio implementare la propria versione di cronometro utilizzando DateTime.Now

Per inciso al EDIT sopra: non utilizzare questo metodo per determinare il tempo trascorso! Non funziona bene quando:

  • elemento della lista
  • l'orologio o il fuso orario è in fase di
  • si avvia ora legale o estremità
  • l'orologio è comunque affidabile (ad esempio all'interno di una VM)

... e, probabilmente, una serie di altre condizioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top