Как делают Вас классы модульного теста то использование таймеры внутренне?

Когда методы упоминаются как .methodName (), это обычно означает, что это методы, существующие во встроенных классах Java. Методы .substring () или .indexOf (), которые вы здесь упомянули, взяты из встроенного Java-класса String. Эти методы могут быть использованы для любой строковой переменной. Пример:

String foo = "abc";
System.out.println(foo.indexOf("c"));

Когда вы начинаете решать задачи кодирования, начинайте искать, если встроенная функция уже существует для чего-то подобного. Вы можете легко найти это в документации Java или просто искать в Google.

10
задан George Mauer 18 May 2009 в 21:43
поделиться

7 ответов

Я извлекаю таймер из объекта, который реагирует на тревогу. В Java вы можете передать ему, например, ScheduledExecutorService. В модульных тестах я передаю ему реализацию, которой я могу управлять детерминированно, например DeterministicScheduler jMock.

8
ответ дан 3 December 2019 в 22:01
поделиться

Похоже, нужно издеваться над таймером, но, увы ... после быстрого поиска в Google этот другой вопрос SO с некоторыми ответами был наверху поисковый результат. Но потом я понял, что вопрос касается классов, использующих таймеры внутри себя, не так ли. Во всяком случае, при программировании игры / движка - вы иногда передаете таймеры в качестве ссылочных параметров конструкторам - что, я думаю, сделало бы их издевательство снова возможным? Но опять же, я нуб-программист ^^

1
ответ дан 3 December 2019 в 22:01
поделиться

Обычно я с этим справляюсь

  1. Установите таймер на каждые 100 миллисекунд и прикиньте, что, скорее всего, мой поток к тому времени будет переключен. Это неудобно и приводит к несколько неопределенным результатам.
  2. Свяжите истекшее событие таймера с общедоступным или защищенным внутренним событием Tick (). Затем из теста установите интервал таймера на что-то очень большое и вызовите метод Tick () вручную из теста. Это дает вам детерминированные тесты, но есть некоторые вещи, которые вы просто не можете протестировать с помощью этого подхода.
0
ответ дан 3 December 2019 в 22:01
поделиться

Я реорганизовываю их так, чтобы временное значение было параметром метода, а затем создайте другой метод, который ничего не делает, кроме как передает правильный параметр. Таким образом, все фактическое поведение изолировано и легко проверяется на всех необычных граничных случаях, оставляя непроверенной только очень тривиальную вставку параметров.

В качестве чрезвычайно тривиального примера, если бы я начал с этого:

public long timeElapsedSinceJan012000() 
{
   Date now = new Date();
   Date jan2000 = new Date(2000, 1, 1);  // I know...deprecated...bear with me
   long difference = now - jan2000;
   return difference;
}

Я бы реорганизовал это, и модульное тестирование второго метода:

public long timeElapsedSinceJan012000() 
{
   return calcDifference(new Date());
}

public long calcDifference(Date d) {
   Date jan2000 = new Date(2000, 1, 1);
   long difference = d - jan2000;
   return difference;
}
0
ответ дан 3 December 2019 в 22:01
поделиться

Это то, что я использую. Я нашел его в книге: Test Driven - Practical TDD and Acceptance TDD for Java Developers Лассе Коскела.

public interface TimeSource {
    long millis();
}


public class SystemTime {

    private static TimeSource source = null;

    private static final TimeSource DEFAULTSRC =
        new TimeSource() {
        public long millis() {
            return System.currentTimeMillis();
        }
    };


    private static TimeSource getTimeSource() {
        TimeSource answer;
        if (source == null) {
            answer = DEFAULTSRC;
        } else {
            answer = source;
        }
        return answer;
    }

    public static void setTimeSource(final TimeSource timeSource) {
        SystemTime.source = timeSource;
    }

    public static void reset() {
        setTimeSource(null);
    }

    public static long asMillis() {
        return getTimeSource().millis();
    }

    public static Date asDate() {
        return new Date(asMillis());
    }

}

Обратите внимание, что источником времени по умолчанию, DEFAULTSRC, является System.currentTimeMillis (). Заменяется в модульных тестах; однако нормальным поведением является стандартное системное время.

Здесь оно используется:

public class SimHengstler {

    private long lastTime = 0;

    public SimHengstler() {
        lastTime = SystemTime.asMillis();  //System.currentTimeMillis();
    }
}

А вот модульный тест:

import com.company.timing.SystemTime;
import com.company.timing.TimeSource;

public class SimHengstlerTest {
    @After
    public void tearDown() {
        SystemTime.reset();
    }

    @Test
    public final void testComputeAccel() {
        // Setup
        setStartTime();
        SimHengstler instance = new SimHengstler();
        setEndTime(1020L);
    }
    private void setStartTime() {
        final long fakeStartTime = 1000L;
        SystemTime.setTimeSource(new TimeSource() {
            public long millis() {
                return fakeStartTime;
            }
        });
    }
    private void setEndTime(final long t) {
        final long fakeEndTime = t;  // 20 millisecond time difference
        SystemTime.setTimeSource(new TimeSource() {
            public long millis() {
                return fakeEndTime;
            }
        });
    }

В модульном тесте я заменил TimeSource только на номер, который был установлен до 1000 миллисекунд. Это будет время начала. При вызове setEndTime () я ввожу 1020 миллисекунд в качестве времени окончания. Это дало мне управляемую разницу во времени в 20 миллисекунд.

В производственном коде нет тестового кода, только получение обычного Systemtime.

3
ответ дан 3 December 2019 в 22:01
поделиться

Я понимаю, что это вопрос Java, но может быть интересно показать, как это делается в мире Perl. Вы можете просто переопределить основные функции времени в своих тестах. :) Это может показаться ужасающим, но это означает, что вам не нужно вводить много дополнительных косвенных указаний в ваш производственный код только для того, чтобы проверить его. Test :: MockTime - один из примеров. Замораживание времени в вашем тесте значительно упрощает некоторые вещи. Например, эти щекотливые неатомные тесты на сравнение времени, в которых вы запускаете что-то в момент X и в то время, когда вы проверяете его X + 1. В приведенном ниже коде есть пример.

Если говорить более условно, недавно у меня был класс PHP для извлечения данных из внешней базы данных. Я хотел, чтобы это происходило не чаще одного раза в X секунд. Чтобы проверить это, я указываю время последнего обновления и интервал времени обновления как атрибуты объекта. Изначально я сделал их константами, поэтому это изменение для тестирования также улучшило код. Тогда тест может поиграть с этими значениями следующим образом:

function testUpdateDelay() {
    $thing = new Thing;

    $this->assertTrue($thing->update,  "update() runs the first time");

    $this->assertFalse($thing->update, "update() won't run immediately after");

    // Simulate being just before the update delay runs out
    $just_before = time() - $thing->update_delay + 2;
    $thing->update_ran_at = $just_before;
    $this->assertFalse($thing->update, "update() won't run just before the update delay runs out");
    $this->assertEqual($thing->update_ran_at, $just_before, "update_ran_at unchanged");

    // Simulate being just after
    $just_after = time() - $thing->update_delay - 2;
    $thing->update_ran_at = $just_after;
    $this->assertTrue($thing->update, "update() will run just after the update delay runs out");

    // assertAboutEqual() checks two numbers are within N of each other.
    // where N here is 1.  This is to avoid a clock tick between the update() and the
    // check
    $this->assertAboutEqual($thing->update_ran_at, time(), 1, "update_ran_at updated");
}
0
ответ дан 3 December 2019 в 22:01
поделиться

Если вы ищете ответы на эту проблему, вам может быть интересно это блог: http://thorstenlorenz.blogspot.com/2009/07/mocking-timer.html

В нем я объясняю способ переопределения обычного поведения класса System.Timers.Timer, чтобы он запускался Start ().

Вот краткая версия:

class FireOnStartTimer : System.Timers.Timer
{
public new event System.Timers.ElapsedEventHandler Elapsed;

public new void Start()
{
  this.Elapsed.Invoke(this, new EventArgs() as System.Timers.ElapsedEventArgs);
}
}

Конечно, для этого требуется, чтобы вы могли передать таймер в тестируемый класс. Если это невозможно, то дизайн класса ошибочен, когда речь идет о тестируемости, поскольку он не поддерживает внедрение зависимостей. Если можете, измените его дизайн. В противном случае вам может не повезти и вы не сможете ничего проверить в этом классе, который включает его внутренний таймер.

Для более подробного объяснения посетите блог.

4
ответ дан 3 December 2019 в 22:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: