Нужно протестировать внутреннюю реализацию или только протестировать общедоступное поведение?

Я считаю, что проблема в startAfter(null). Когда вы сортируете в порядке возрастания, сначала идут нулевые документы, а затем ненулевые документы. Точный порядок см. В документации Firebase о порядке типов значений .

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

Я предлагаю удалить startAfter(null), пока у вас не будет значения для него.

44
задан ChrisW 26 May 2009 в 14:13
поделиться

15 ответов

Моя практика состоит в том, чтобы тестировать внутренние компоненты через общедоступный API / UI. Если какой-то внутренний код недоступен извне, я выполняю рефакторинг для его удаления.

18
ответ дан 26 November 2019 в 22:10
поделиться

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

0
ответ дан 26 November 2019 в 22:10
поделиться

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

каждому из них может потребоваться «имитировать» компонент другого, чтобы у них было что-то (макет), на котором можно протестировать свой собственный компонент, прежде чем их компонент будет сочтен готовым для последующего «интеграционного тестирования», и до того, как другая команда предоставит свой компонент против

  • Если вы разрабатываете всю систему, вы можете расширить всю систему ... например, разработать новое поле графического интерфейса пользователя, новое поле базы данных, новую бизнес-транзакцию и одну новую системный / функциональный тест, все как часть одной итерации, без необходимости разрабатывать «макеты» какого-либо уровня (так как вместо этого вы можете протестировать реальный объект).

  • 0
    ответ дан 26 November 2019 в 22:10
    поделиться

    Я лично тестирую и защищенные части, потому что они "общедоступны" для унаследованных типов ...

    0
    ответ дан 26 November 2019 в 22:10
    поделиться

    Я согласен с тем, что покрытие кода в идеале должно быть 100%. Это не обязательно означает, что 60 строк кода будут иметь 60 строк тестового кода, но проверяется каждый путь выполнения. Единственное, что раздражает больше, чем ошибка, - это еще не запущенная ошибка.

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

    0
    ответ дан 26 November 2019 в 22:10
    поделиться

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

    В ограниченной практике TDD, которую я имел, я ' Мы видели, как это помогает мне избавиться от модульных тестов для каждого логического условия, создаваемого кодом. Я не совсем уверен, что 100% логических функций моего частного кода доступны через мои общедоступные интерфейсы. Практика TDD кажется дополнением к этой метрике, но все же есть скрытые функции, не разрешенные общедоступными API.

    Я полагаю, вы могли бы сказать, что эта практика защищает меня от будущих дефектов в моих общедоступных интерфейсах. Либо вы сочтете это полезным (и позволит вам быстрее добавлять новые функции), либо вы обнаружите, что это пустая трата времени.

    Я полагаю, вы могли бы сказать, что эта практика защищает меня от будущих дефектов в моих общедоступных интерфейсах. Либо вы сочтете это полезным (и позволит вам быстрее добавлять новые функции), либо вы обнаружите, что это пустая трата времени.

    Я полагаю, вы могли бы сказать, что эта практика защищает меня от будущих дефектов в моих общедоступных интерфейсах. Либо вы сочтете это полезным (и позволит вам быстрее добавлять новые функции), либо вы обнаружите, что это пустая трата времени.

    2
    ответ дан 26 November 2019 в 22:10
    поделиться

    На этот вопрос было получено много отличных ответов, но я хочу добавить несколько собственных замечаний. В качестве предисловия: я консультант крупной компании, которая предоставляет технологические решения широкому кругу крупных клиентов. Я говорю это потому, что, по моему опыту, от нас требуется гораздо более тщательное тестирование, чем от большинства магазинов программного обеспечения (за исключением, возможно, разработчиков API). Вот некоторые шаги, которые мы выполняем для обеспечения качества:

    • Внутренний модульный тест:
      Разработчики должны создавать модульные тесты для всего кода, который они пишут (читайте: каждый метод). Модульные тесты должны охватывать положительные тестовые условия (работает ли мой метод?) И отрицательные тестовые условия (генерирует ли метод исключение ArgumentNullException, когда один из моих обязательных аргументов равен нулю?). Обычно мы включаем эти тесты в процесс сборки с помощью такого инструмента, как CruiseControl.net
    • System Test / Assembly Test:
      Иногда этот шаг называется иначе, но именно тогда мы начинаем тестирование общедоступных функций. Как только вы узнаете, что все ваши отдельные устройства работают должным образом, вы захотите узнать, что ваши внешние функции также работают так, как вы думаете, что они должны. Это форма функциональной проверки, поскольку цель состоит в том, чтобы определить, работает ли вся система должным образом. Обратите внимание, что это не включает никаких точек интеграции. Для системного тестирования вы должны использовать макеты интерфейсов вместо реальных, чтобы вы могли контролировать вывод и строить на его основе тестовые примеры.
    • Тест интеграции системы:
      На этом этапе процесса вы хотите для подключения ваших точек интеграции к системе. Например, Если вы используете систему обработки кредитных карт, вы захотите включить действующую систему на этом этапе, чтобы убедиться, что она по-прежнему работает. Вы хотели бы выполнить тестирование, подобное тесту системы / сборки.
    • Функциональная проверка:
      Функциональная проверка - это пользователи, запускающие систему или использующие API, чтобы убедиться, что она работает должным образом. Если вы создали систему выставления счетов, это этап, на котором вы будете выполнять свои тестовые сценарии от начала до конца, чтобы убедиться, что все работает так, как вы это разработали. Очевидно, что это критический этап в процессе, поскольку он показывает, выполнили ли вы свою работу.
    • Certification Test:
      Здесь вы помещаете реальных пользователей перед системой и позволяете им попробовать. , В идеале вы уже протестировали свой пользовательский интерфейс на каком-то этапе с заинтересованными сторонами, но на этом этапе вы узнаете, нравится ли ваш продукт вашей целевой аудитории. Возможно, вы слышали, что другие поставщики называют это чем-то вроде «релиз-кандидата». Если на этом этапе все пойдет хорошо, вы знаете, что готовы приступить к производству. Сертификационные тесты всегда должны выполняться в той же среде, которую вы будете использовать для производства (или, по крайней мере, в идентичной среде).

    Конечно, я знаю, что не все следуют этому процессу, но если вы посмотрите на него от начала до конца В конце вы можете начать видеть преимущества отдельных компонентов. Я не включил такие вещи, как тесты проверки сборки, так как они происходят в другой график (например, ежедневно). Я лично считаю, что модульные тесты критичны, потому что они дают вам глубокое понимание того, какой конкретный компонент вашего приложения дает сбой в каком конкретном варианте использования. Модульные тесты также помогут вам определить, какие методы работают правильно, чтобы вы не тратили время на изучение их для получения дополнительной информации о сбое, когда с ними все в порядке.

    Конечно, модульные тесты также могут ошибаться, но если вы разрабатываете свои тестовые примеры на основе своей функциональной / технической спецификации (она у вас есть, верно?;)), у вас не должно возникнуть особых проблем.

    но если вы разрабатываете свои тестовые примеры на основе своей функциональной / технической спецификации (она у вас есть, верно?;)), у вас не должно возникнуть особых проблем.

    но если вы разрабатываете свои тестовые примеры на основе своей функциональной / технической спецификации (она у вас есть, верно?;)), у вас не должно возникнуть особых проблем.

    8
    ответ дан 26 November 2019 в 22:10
    поделиться

    нет ничего плохого. Ответ очень прост: вы описываете функциональное тестирование, которое является важной частью обеспечения качества программного обеспечения. Тестирование внутренней реализации - это модульное тестирование, которое является другой частью QA программного обеспечения с другой целью. Вот почему вы чувствуете, что люди не согласны с вашим подходом.

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

    Unit-test здесь, чтобы проверить, что 10 строк кода, которые вы только что написали, делают то, что должны. Это дает вам больше уверенности в вашем коде.

    Оба они дополняют друг друга. Если вы работаете с существующей системой, возможно, первое, над чем стоит поработать, - это функциональное тестирование. Но как только вы добавите код, модульное тестирование тоже будет хорошей идеей.

    30
    ответ дан 26 November 2019 в 22:10
    поделиться

    У меня нет моей копии Лакоса передо мной, поэтому вместо того, чтобы цитировать, я просто укажу, что он справляется лучше, чем я объясню почему тестирование важно на всех уровнях.

    Проблема с тестированием только «публичного поведения» заключается в том, что такой тест дает очень мало информации. Он обнаружит много ошибок (точно так же, как компилятор обнаружит много ошибок), но не может сказать вам, где они находятся. Плохо реализованный модуль часто возвращает хорошие значения в течение длительного времени, а затем перестает делать это при изменении условий; если бы этот модуль тестировался напрямую, тот факт, что он был реализован плохо, стал бы очевидным раньше.

    Наилучший уровень детализации теста - это уровень модуля. Проведите тесты для каждого устройства через его интерфейс (ы). Это позволяет вам проверять и задокументировать ваши представления о том, как ведет себя каждый компонент, что, в свою очередь, позволяет вам тестировать зависимый код, тестируя только новые функциональные возможности, которые он вводит, что, в свою очередь, делает тесты короткими и целевыми. В качестве бонуса он сохраняет тесты с кодом, который они тестируют.

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

    9
    ответ дан 26 November 2019 в 22:10
    поделиться

    использовать относительный путь

    главной страницы может быть: /index.html

    дополнительная страница: Это аргумент, который следует сделать, чтобы быть хорошим программистом, вам нужно беспокоиться о крайних случаях, но чтобы быть хорошим тестером, вы одержимо беспокоитесь ;-) Кроме того, тестировщики могут быть дешевле, поэтому, возможно, стоит создать отдельную команду тестирования по этой причине.

    Я думаю, что главный вопрос заключается в следующем: какая методология лучше всего подходит для поиска ошибок в программном обеспечении? Недавно я посмотрел видео (без ссылки, извините), в котором говорится, что рандомизированное тестирование дешевле и так же эффективно, как тесты, созданные человеком.

    0
    ответ дан 26 November 2019 в 22:10
    поделиться

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

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

    Раньше я думал точно так же, как CrisW демонстрирует в этом вопросе - что тестирование на более высоких уровнях было бы лучше, но после того, как я получил некоторый опыт, мои мысли модерируются к чему-то между этим и «каждый класс должен иметь тестовый класс». Каждый модуль должен иметь тесты, но я предпочитаю определять свои модули немного иначе, чем когда-то. Это могут быть «компоненты», о которых говорит CrisW, но очень часто это также всего лишь один класс.

    Кроме того, функциональные тесты могут быть достаточно хорошими, чтобы доказать, что ваша система делает то, что она должна делать, но если вы хотите Чтобы привести ваш дизайн в действие примерами / тестами (TDD / BDD), естественным следствием являются тесты нижнего рычага. Вы можете выбросить эти низкоуровневые тесты, когда закончите внедрение, но это будет пустой тратой - тесты являются положительным побочным эффектом. Если вы решите провести радикальный рефакторинг, делающий ваши низкоуровневые тесты недействительными, тогда вы выбросите их и один раз напишете новые.

    Разделение цели тестирования / проверки вашего программного обеспечения и использования тестов / примеров для управления вашим дизайном / реализацией может прояснить это обсуждение много.

    Обновление: Кроме того, есть два основных способа выполнения TDD: снаружи внутрь и наизнанку. BDD продвигает внешнее вовнутрь, что ведет к тестам / спецификациям более высокого уровня. Однако если вы начнете с деталей, вы напишете подробные тесты для всех классов.

    Есть два основных способа выполнения TDD: снаружи внутрь и наизнанку. BDD продвигает внешнее вовнутрь, что ведет к тестам / спецификациям более высокого уровня. Однако если вы начнете с деталей, вы напишете подробные тесты для всех классов.

    Есть два основных способа выполнения TDD: снаружи внутрь и наизнанку. BDD продвигает внешнее вовнутрь, что ведет к тестированию / спецификациям более высокого уровня. Однако если вы начнете с деталей, вы напишете подробные тесты для всех классов.

    1
    ответ дан 26 November 2019 в 22:10
    поделиться

    Функциональные тесты можно кодировать; Все в порядке. Но вам следует проверить, используя тестовое покрытие для реализации, чтобы продемонстрировать, что весь тестируемый код имеет цель относительно функциональных тестов и что он действительно делает что-то важное.

    2
    ответ дан 26 November 2019 в 22:10
    поделиться

    Я согласен с большинством сообщений здесь, однако я бы добавил следующее:

    Первоочередной задачей является тестирование общедоступных интерфейсов, затем защищенных, а затем частных.

    Обычно открытые и защищенные интерфейсы представляют собой совокупность частных и защищенных интерфейсов.

    Лично: Вы должны все проверить. При наличии сильного набора тестов для небольших функций вы получите большую уверенность в том, что эти скрытые методы работают. Также я согласен с другим комментарием по поводу рефакторинга. Покрытие кода поможет вам определить, где находятся лишние биты кода, и при необходимости реорганизовать их.

    1
    ответ дан 26 November 2019 в 22:10
    поделиться

    Это зависит от вашего дизайна и от того, где будет наибольшая ценность. Один тип приложений может требовать другого подхода к другому. Иногда с помощью модульных тестов вы не уловите ничего интересного, тогда как функциональные / интеграционные тесты преподносят сюрпризы. Иногда модульные тесты терпят неудачу сотни раз во время разработки, выявляя множество ошибок в процессе разработки.

    Иногда это тривиально. То, как некоторые классы связаны вместе, делает окупаемость вложений в тестирование каждого пути менее привлекательной, поэтому вы можете просто провести черту и перейти к более важным / сложным / часто используемым предметам.

    Иногда недостаточно просто протестировать общедоступный API, потому что внутри скрывается некоторая особенно интересная логика, и приводить систему в движение и использовать эти конкретные пути слишком болезненно. Который' s, когда его внутренняя проверка окупается.

    В наши дни я обычно пишу множество (часто чрезвычайно) простых классов, которые лучше всего справляются с одной или двумя вещами. Затем я реализую желаемое поведение, делегируя все сложные функции этим внутренним классам. Т.е. у меня есть несколько более сложные взаимодействия, но действительно простые классы.

    Если я изменю свою реализацию и мне придется реорганизовать некоторые из этих классов, мне обычно все равно. Я стараюсь как можно лучше изолировать свои тесты, поэтому часто достаточно просто изменить, чтобы они снова заработали. Однако, если мне действительно приходится отбрасывать некоторые из внутренних классов, я часто заменяю несколько классов и вместо этого пишу несколько совершенно новых тестов. Я часто слышу, как люди жалуются на необходимость поддерживать тесты в актуальном состоянии после рефакторинга и, хотя иногда это неизбежно и утомительно, если уровень детализации достаточно хорош, обычно не имеет большого значения выбросить некоторые код + тесты.

    Я считаю, что это одно из основных различий между дизайном, ориентированным на проверку, и отсутствием беспокойства.

    0
    ответ дан 26 November 2019 в 22:10
    поделиться

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

    Но вы должны иметь возможность развивать дублирующую службу или компонент, используя подход Test First. т.е. определите общедоступный интерфейс и проверьте его на базовую функциональность. это не удастся. Реализуйте эту базовую функциональность с помощью API фоновых классов. Напишите API, чтобы удовлетворить только этот первый тестовый пример. Затем продолжайте спрашивать, что сервис может делать больше и развиваться.

    Единственное сбалансированное решение, которое следует принять, - это разбить одну большую услугу или компонент на несколько меньших сервисов и компонентов, которые можно использовать повторно. Если вы твердо уверены, что компонент можно повторно использовать в разных проектах. Затем для этого компонента должны быть написаны автоматические тесты. Но опять же, тесты, написанные для большой службы или компонента, должны дублировать функционально уже протестированные компоненты.

    Некоторые люди могут прийти к теоретической дискуссии о том, что это не модульное тестирование. Так что все в порядке. Основная идея - иметь автоматизированные тесты для тестирования вашего программного обеспечения. Так что, если это не на уровне единицы. Если он охватывает интеграцию с базой данных (которую вы контролируете), то это только лучше.

    Дайте мне знать, если вы разработали какой-либо хороший процесс, который работает для вас .. с момента вашего первого сообщения ..

    с уважением Амит

    1
    ответ дан 26 November 2019 в 22:10
    поделиться
    Другие вопросы по тегам:

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