2009-11-17 6 views
1

J'ai écrit une fonctionnalité pour ma bibliothèque Rubikon qui affiche un throbber (un — tournant comme vous avez pu le voir dans d'autres applications de console) tant qu'un autre code est en cours d'exécution.Test du code critique de temps

Pour tester cette fonctionnalité, je capture la sortie du throbber dans un StringIO et la compare avec la valeur attendue. Comme le throbber n'est affiché que tant que l'autre code est en cours d'exécution, le contenu du IO s'allonge lorsque le code est plus long. Dans mes tests, je fais un simple sleep 1 et devrait avoir un retard constant de 1 seconde. Cela fonctionne la plupart du temps, mais parfois (apparemment en raison de facteurs externes comme la charge lourde sur le CPU), il échoue, parce que le code ne fonctionne pas pendant 1 seconde, mais pour un peu plus, de sorte que le throbber imprime quelques personnages.

Ma question est la suivante: Y a-t-il une possibilité de tester ces fonctionnalités critiques dans Ruby?

Répondre

2

À partir de votre dépôt GitHub, je trouve ce test pour la classe throbber:

should 'work correctly' do 
    ostream = StringIO.new 
    thread = Thread.new { sleep 1 } 
    throbber = Throbber.new(ostream, thread) 
    thread.join 
    throbber.join 
    assert_equal " \b-\b\\\b|\b/\b", ostream.string 
end 

Je suppose qu'un itère throbber plus ['-', '\', '|', '/'], avant chaque écriture en supprimant les espaces, une fois par seconde. Considérez le test suivant:

should 'work correctly' do 
    ostream = StringIO.new 
    started_at = Time.now 
    ended_at = nil 
    thread = Thread.new { sleep 1; ended_at = Time.now } 
    throbber = Throbber.new(ostream, thread) 
    thread.join 
    throbber.join 
    duration = ended_at - started_at 
    iterated_chars = " -\\|/" 
    expected = "" 
    if duration >= 1 
    # After n seconds we should have n copies of " -\\|/", excluding \b for now 
    expected << iterated_chars * duration.to_i 
    end 
    # Next append the characters we'd get from working for fractions of a second: 
    remainder = duration - duration.to_i 
    expected << iterated_chars[0..((iterated_chars.length*remainder).to_i)] if remainder > 0.0 
    expected = expected.split('').join("\b") + "\b" 
    assert_equal expected, ostream.string 
end 

La dernière cession de expected est un peu désagréable, mais je fait l'hypothèse que le throbber écrirait paires caractère/backspace atomiquement. Si ce n'est pas le cas, vous devriez pouvoir insérer la séquence d'échappement \ b dans la chaîne iterated_chars et supprimer entièrement la dernière affectation.

+0

Ça sonne bien, je vais vérifier celui-ci. – Koraktor

1

Cette question est similaire (je pense, barbante Je ne suis pas complètement sûr) à this one:

système d'exploitation en temps réel ne peut vous donner une telle précision. Vous pouvez supposer Thread.Sleep a une précision de environ 20 ms vous pouvez donc, en théorie sommeil jusqu'à ce que le temps désiré - le temps réel est d'environ 20 ms puis rotation pendant 20 ms, mais vous devrez gaspillez ces 20 ms. Et même que ne garantit pas que vous obtiendrez des résultats réels de temps, le planificateur pourrait bien prendre votre fil à juste au moment où il était sur le point d'exécuter la partie pertinente (juste après le filage)

Le problème n'est pas rubby (peut-être, je ne suis pas expert en ruby), le problème est les capacités en temps réel de votre système d'exploitation.

+0

Je sais que je ne peux pas m'attendre à un comportement en temps réel d'un système d'exploitation non-temps réel et surtout d'un langage de script comme Ruby. Ma question n'est pas d'éliminer les retards pour obtenir un comportement en temps réel, je veux juste éliminer les effets secondaires dans les tests unitaires. – Koraktor