Разработка через тестирование

Поделись знанием:
Перейти к: навигация, поиск
Разработка программного обеспечения
Процесс разработки ПО
Шаги процесса

Анализ • Проектирование • Программирование • Документирование • Тестирование

Модели

Итеративная • Спиральная • Каскадная • V-Model • Dual Vee Model

Методологии

Agile (XP, Lean, Scrum, FDD и др.) • Cleanroom • OpenUP • RAD • RUP • MSF • DSDM • TDD

Сопутствующие дисциплины

Конфигурационное управление • Управление проектами • Управление требованиями

Разработка через тестирование (англ. test-driven development, TDD) — техника разработки программного обеспечения, которая основывается на повторении очень коротких циклов разработки: сначала пишется тест, покрывающий желаемое изменение, затем пишется код, который позволит пройти тест, и под конец проводится рефакторинг нового кода к соответствующим стандартам. Кент Бек, считающийся изобретателем этой техники, утверждал в 2003 году, что разработка через тестирование поощряет простой дизайн и внушает уверенность (англ. inspires confidence)[1].

В 1999 году при своём появлении разработка через тестирование была тесно связана с концепцией «сначала тест» (англ. test-first), применяемой в экстремальном программировании[2], однако позже выделилась как независимая методология.[3].

Тест — это процедура, которая позволяет либо подтвердить, либо опровергнуть работоспособность кода. Когда программист проверяет работоспособность разработанного им кода, он выполняет тестирование вручную.





Требования

Разработка через тестирование требует от разработчика создания автоматизированных модульных тестов, определяющих требования к коду непосредственно перед написанием самого кода. Тест содержит проверки условий, которые могут либо выполняться, либо нет. Когда они выполняются, говорят, что тест пройден. Прохождение теста подтверждает поведение, предполагаемое программистом. Разработчики часто пользуются библиотеками для тестирования (англ. testing frameworks) для создания и автоматизации запуска наборов тестов. На практике модульные тесты покрывают критические и нетривиальные участки кода. Это может быть код, который подвержен частым изменениям, код, от работы которого зависит работоспособность большого количества другого кода, или код с большим количеством зависимостей.

Среда разработки должна быстро реагировать на небольшие модификации кода. Архитектура программы должна базироваться на использовании множества сильно связанных компонентов, которые слабо сцеплены друг с другом, благодаря чему тестирование кода упрощается.

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

Разумеется, к тестам применяются те же требования стандартов кодирования, что и к основному коду.

Цикл разработки через тестирование

Приведенная последовательность действий основана на книге Кента Бека «Разработка через тестирование: на примере» (англ. Test Driven Development: By Example).[1]

Добавление теста

При разработке через тестирование, добавление каждой новой функциональности (англ. feature) в программу начинается с написания теста. Неизбежно этот тест не будет проходить, поскольку соответствующий код ещё не написан. (Если же написанный тест прошёл, это означает, что либо предложенная «новая» функциональность уже существует, либо тест имеет недостатки.) Чтобы написать тест, разработчик должен чётко понимать предъявляемые к новой возможности требования. Для этого рассматриваются возможные сценарии использования и пользовательские истории. Новые требования могут также повлечь изменение существующих тестов. Это отличает разработку через тестирование от техник, когда тесты пишутся после того, как код уже написан: она заставляет разработчика сфокусироваться на требованиях до написания кода — тонкое, но важное отличие.

Запуск всех тестов: убедиться, что новые тесты не проходят

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

Написать код

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

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

Запуск всех тестов: убедиться, что все тесты проходят

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

Рефакторинг

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

Повторить цикл

Описанный цикл повторяется, реализуя всё новую и новую функциональность. Шаги следует делать небольшими, от 1 до 10 изменений между запусками тестов. Если новый код не удовлетворяет новым тестам или старые тесты перестают проходить, программист должен вернуться к отладке. При использовании сторонних библиотек не следует делать настолько небольшие изменения, которые буквально тестируют саму стороннюю библиотеку[3], а не код, её использующий, если только нет подозрений, что библиотека содержит ошибки.

Стиль разработки

Разработка через тестирование тесно связана с такими принципами как «делай проще, дурачок» (англ. keep it simple, stupid, KISS) и «вам это не понадобится» (англ. you ain’t gonna need it, YAGNI). Дизайн может быть чище и яснее, при написании лишь того кода, который необходим для прохождения теста.[1] Кент Бек также предлагает принцип «подделай, пока не сделаешь» (англ. fake it till you make it). Тесты должны писаться для тестируемой функциональности. Считается, что это имеет два преимущества. Это помогает убедиться, что приложение пригодно для тестирования, поскольку разработчику придется с самого начала обдумать то, как приложение будет тестироваться. Это также способствует тому, что тестами будет покрыта вся функциональность. Когда функциональность пишется до тестов, разработчики и организации склонны переходить к реализации следующей функциональности, не протестировав существующую.

Идея проверять, что вновь написанный тест не проходит, помогает убедиться, что тест реально что-то проверяет. Только после этой проверки следует приступать к реализации новой функциональности. Этот приём, известный как «красный/зеленый/рефакторинг», называют «мантрой разработки через тестирование». Под красным здесь понимают не прошедшие тесты, а под зелёным — прошедшие.

Отработанные практики разработки через тестирование привели к созданию техники «разработка через приёмочное тестирование» (англ. Acceptance Test-driven development, ATDD), в котором критерии описанные заказчиком автоматизируются в приемочные тесты, используемые потом в обычном процессе разработки через модульное тестирование (англ. unit test-driven development, UTDD).[4] Этот процесс позволяет гарантировать, что приложение удовлетворяет сформулированным требованиям. При разработке через приёмочное тестирование, команда разработчиков сконцентрирована на четкой задаче: удовлетворить приемочные тесты, которые отражают соответствующие требования пользователя.

Приёмочные (функциональные) тесты (англ. customer tests, acceptance tests) — тесты, проверяющие функциональность приложения на соответствие требованиям заказчика. Приёмочные тесты проходят на стороне заказчика. Это помогает ему быть уверенным в том, что он получит всю необходимую функциональность.

Преимущества

Исследование 2005 года показало, что использование разработки через тестирование предполагает написание большего количества тестов, в свою очередь, программисты, пишущие больше тестов, склонны быть более продуктивными.[5] Гипотезы связывающие качество кода с TDD были неубедительны.[6]

Программисты, использующие TDD на новых проектах, отмечают, что они реже ощущают необходимость использовать отладчик. Если некоторые из тестов неожиданно перестают проходить, откат к последней версии, которая проходит все тесты, может быть более продуктивным, нежели отладка.[7]

Разработка через тестирование предлагает больше, чем просто проверку корректности, она также влияет на дизайн программы. Изначально сфокусировавшись на тестах, проще представить, какая функциональность необходима пользователю. Таким образом, разработчик продумывает детали интерфейса до реализации. Тесты заставляют делать свой код более приспособленным для тестирования. Например, отказываться от глобальных переменных, одиночек (singletons), делать классы менее связанными и легкими для использования. Сильно связанный код или код, который требует сложной инициализации, будет значительно труднее протестировать. Модульное тестирование способствует формированию четких и небольших интерфейсов. Каждый класс будет выполнять определенную роль, как правило, небольшую. Как следствие, зависимости между классами будут снижаться, а зацепление повышаться. Контрактное программирование (англ. design by contract) дополняет тестирование, формируя необходимые требования через утверждения (англ. assertions).

Несмотря на то, что при разработке через тестирование требуется написать большее количество кода, общее время, затраченное на разработку, обычно оказывается меньше. Тесты защищают от ошибок. Поэтому время, затрачиваемое на отладку, снижается многократно.[8] Большое количество тестов помогает уменьшить количество ошибок в коде. Устранение дефектов на более раннем этапе разработки, препятствует появлению хронических и дорогостоящих ошибок, приводящих к длительной и утомительной отладке в дальнейшем.

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

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

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

Тесты могут использоваться в качестве документации. Хороший код расскажет о том, как он работает, лучше любой документации. Документация и комментарии в коде могут устаревать. Это может сбивать с толку разработчиков, изучающих код. А так как документация, в отличие от тестов, не может сказать, что она устарела, такие ситуации, когда документация не соответствует действительности — не редкость.

Слабые места

  • Существуют задачи, которые невозможно (по крайней мере, на текущий момент) решить только при помощи тестов. В частности, TDD не позволяет механически продемонстрировать адекватность разработанного кода в области безопасности данных и взаимодействия между процессами. Безусловно, безопасность основана на коде, в котором не должно быть дефектов, однако она основана также на участии человека в процедурах защиты данных. Тонкие проблемы, возникающие в области взаимодействия между процессами, невозможно с уверенностью воспроизвести, просто запустив некоторый код.
  • Разработку через тестирование сложно применять в тех случаях, когда для тестирования необходимо прохождение функциональных тестов. Примерами может быть: разработка интерфейсов пользователя, программ, работающих с базами данных, а также того, что зависит от специфической конфигурации сети. Разработка через тестирование не предполагает большого объёма работы по тестированию такого рода вещей. Она сосредотачивается на тестировании отдельно взятых модулей, используя mock-объекты для представления внешнего мира.
  • Требуется больше времени на разработку и поддержку, а одобрение со стороны руководства очень важно. Если у организации нет уверенности в том, что разработка через тестирование улучшит качество продукта, то время, потраченное на написание тестов, может рассматриваться как потраченное впустую.[9]
  • Модульные тесты, создаваемые при разработке через тестирование, обычно пишутся теми же, кто пишет тестируемый код. Если разработчик неправильно истолковал требования к приложению, и тест, и тестируемый модуль будут содержать ошибку.
  • Большое количество используемых тестов могут создать ложное ощущение надежности, приводящее к меньшему количеству действий по контролю качества.
  • Тесты сами по себе являются источником накладных расходов. Плохо написанные тесты, например, содержат жёстко вшитые строки с сообщениями об ошибках или подвержены ошибкам, дороги при поддержке. Чтобы упростить поддержку тестов следует повторно использовать сообщения об ошибках из тестируемого кода.
  • Уровень покрытия тестами, получаемый в результате разработки через тестирование, не может быть легко получен впоследствии. Исходные тесты становятся всё более ценными с течением времени. Если неудачные архитектура, дизайн или стратегия тестирования приводят к большому количеству непройденных тестов, важно их все исправить в индивидуальном порядке. Простое удаление, отключение или поспешное изменение их может привести к необнаруживаемым пробелам в покрытии тестами.

Видимость кода

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

Из кода теста может не быть доступа к частным (англ. private) полям и методам. Поэтому при модульном тестировании может потребоваться дополнительная работа. В Java, разработчик может использовать отражение (англ. reflection), чтобы обращаться к полям, помеченными как частные.[10] Модульные тесты можно реализовать во внутренних классах, чтобы они имели доступ к членам внешнего класса. В .NET Framework могут применяться разделяемые классы (англ. partial classes) для доступа из теста к частным полям и методам.

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

Не существует единого мнения среди программистов, применяющих разработку через тестирование, о том, насколько осмысленно тестировать частные, защищённые методы, а также данные. Одни убеждены, что достаточно протестировать любой класс только через его публичный интерфейс, поскольку частные переменные — это всего лишь деталь реализации, которая может меняться, и её изменения не должны отражаться на наборе тестов. Другие утверждают, что важные аспекты функциональности могут быть реализованы в частных методах и тестирование их неявно через публичный интерфейс лишь усложнит ситуацию: модульное тестирование предполагает тестирование наименьших возможных модулей функциональности.[11][12]

Fake-, mock-объекты и интеграционные тесты

Модульные тесты тестируют каждый модуль по отдельности. Не важно, содержит ли модуль сотни тестов или только пять. Тесты, используемые при разработке через тестирование, не должны пересекать границы процесса, использовать сетевые соединения. В противном случае прохождение тестов будет занимать большое время, и разработчики будут реже запускать набор тестов целиком. Введение зависимости от внешних модулей или данных также превращает модульные тесты в интеграционные. При этом если один модуль в цепочке ведет себя неправильно, может быть не сразу понятно какой именноК:Википедия:Статьи без источников (тип: не указан)[источник не указан 4249 дней].

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

  1. Везде, где требуется доступ к внешним ресурсам, должен быть объявлен интерфейс, через который этот доступ будет осуществляться. См. принцип инверсии зависимостей (англ. dependency inversion) для обсуждения преимуществ этого подхода независимо от TDD.
  2. Интерфейс должен иметь две реализации. Первая, собственно предоставляющая доступ к ресурсу, и вторая, являющаяся fake- или mock-объектом. Всё, что делают fake-объекты, это добавляют сообщения вида «Объект person сохранен» в лог, чтобы потом проверить правильность поведения. Mock-объекты отличаются от fake- тем, что сами содержат утверждения (англ. assertion), проверяющие поведение тестируемого кода. Методы fake- и mock-объектов, возвращающие данные, можно настроить так, чтобы они возвращали при тестировании одни и те же правдоподобные данные. Они могут эмулировать ошибки так, чтобы код обработки ошибок мог быть тщательно протестирован. Другими примерами fake-служб, полезными при разработке через тестирование, могут быть: служба кодирования, которая не кодирует данные, генератор случайных чисел, который всегда выдает единицу. Fake- или mock-реализации являются примерами внедрения зависимости (англ. dependency injection).

Использование fake- и mock-объектов для представления внешнего мира приводит к тому, что настоящая база данных и другой внешний код не будут протестированы в результате процесса разработки через тестирование. Чтобы избежать ошибок, необходимы тесты реальных реализаций интерфейсов, описанных выше. Эти тесты могут быть отделены от остальных модульных тестов и реально являются интеграционными тестами. Их необходимо меньше, чем модульных, и они могут запускаться реже. Тем не менее, чаще всего они реализуются используя те же библиотеки для тестирования (англ. testing framework), что и модульные тесты.

Интеграционные тесты, которые изменяют данные в базе данных, должны откатывать состоянии базы данных к тому, которое было до запуска теста, даже если тест не прошёл. Для этого часто применяются следующие техники:

  • Метод TearDown, присутствующий в большинстве библиотек для тестирования.
  • try...catch...finally структуры обработки исключений, там где они доступны.
  • Транзакции баз данных.
  • Создание снимка (англ. snapshot) базы данных перед запуском тестов и откат к нему после окончания тестирования.
  • Сброс базы данных в чистое состояние перед тестом, а не после них. Это может быть удобно, если интересно посмотреть состояние базы данных, оставшееся после не прошедшего теста.

Существуют библиотеки Moq, jMock, NMock, EasyMock, Typemock, jMockit, Unitils, Mockito, Mockachino, PowerMock или Rhino Mocks, а также sinon для JavaScript предназначенные упростить процесс создания mock-объектов.

См. также

Напишите отзыв о статье "Разработка через тестирование"

Примечания

  1. 1 2 3 Beck, K. Test-Driven Development by Example, Addison Wesley, 2003
  2. Lee Copeland. [www.computerworld.com/softwaretopics/software/appdev/story/0,10801,66192,00.html Extreme Programming]. Computerworld (December 2001). Проверено 11 января 2011. [www.webcitation.org/61G4iG4ee Архивировано из первоисточника 28 августа 2011].
  3. 1 2 Newkirk, JW and Vorontsov, AA. Test-Driven Development in Microsoft .NET, Microsoft Press, 2004
  4. Koskela, L. «Test Driven: TDD and Acceptance TDD for Java Developers», Manning Publications, 2007
  5. Erdogmus, Hakan; Morisio, Torchiano. [iit-iti.nrc-cnrc.gc.ca/publications/nrc-47445_e.html On the Effectiveness of Test-first Approach to Programming]. Proceedings of the IEEE Transactions on Software Engineering, 31(1). January 2005. (NRC 47445). — «We found that test-first students on average wrote more tests and, in turn, students who wrote more tests tended to be more productive.»  Проверено 14 января 2008. [www.webcitation.org/61G4jTMDZ Архивировано из первоисточника 28 августа 2011].
  6. Proffitt, Jacob [theruntime.com/blogs/jacob/archive/2008/01/22/tdd-proven-effective-or-is-it.aspx TDD Proven Effective! Or is it?]. — «So TDD's relationship to quality is problematic at best. Its relationship to productivity is more interesting. I hope there's a follow-up study because the productivity numbers simply don't add up very well to me. There is an undeniable correlation between productivity and the number of tests, but that correlation is actually stronger in the non-TDD group (which had a single outlier compared to roughly half of the TDD group being outside the 95% band).»  Проверено 21 февраля 2008. [www.webcitation.org/61G4k4frE Архивировано из первоисточника 28 августа 2011].
  7. Llopis, Noel [www.gamesfromwithin.com/articles/0502/000073.html Stepping Through the Looking Glass: Test-Driven Game Development (Part 1)](недоступная ссылка — история). Games from Within (20 February 2005). — «Comparing [TDD] to the non-test-driven development approach, you're replacing all the mental checking and debugger stepping with code that verifies that your program does exactly what you intended it to do.»  Проверено 1 ноября 2007. [web.archive.org/20050222120848/www.gamesfromwithin.com/articles/0502/000073.html Архивировано из первоисточника 22 февраля 2005].
  8. Müller, Matthias M.; Padberg, Frank. [www.ipd.uka.de/mitarbeiter/muellerm/publications/edser03.pdf About the Return on Investment of Test-Driven Development] (PDF) 6. Universität Karlsruhe, Germany. Проверено 1 ноября 2007. [www.webcitation.org/61G4kow2C Архивировано из первоисточника 28 августа 2011].
  9. Loughran, Steve [people.apache.org/~stevel/slides/testing.pdf Testing] (PDF). HP Laboratories (November 6th, 2006). Проверено 12 августа 2009. [www.webcitation.org/61G4lOhjb Архивировано из первоисточника 28 августа 2011].
  10. Burton, Ross [www.onjava.com/pub/a/onjava/2003/11/12/reflection.html Subverting Java Access Protection for Unit Testing]. O'Reilly Media, Inc. (11/12/2003). Проверено 12 августа 2009. [www.webcitation.org/61G4lu7Yy Архивировано из первоисточника 28 августа 2011].
  11. Newkirk, James [blogs.msdn.com/jamesnewkirk/archive/2004/06/07/150361.aspx Testing Private Methods/Member Variables - Should you or shouldn't you]. Microsoft Corporation (7 June 2004). Проверено 12 августа 2009. [www.webcitation.org/61G4mlTOE Архивировано из первоисточника 28 августа 2011].
  12. Stall, Tim [www.codeproject.com/KB/cs/testnonpublicmembers.aspx How to Test Private and Protected methods in .NET]. CodeProject (1 Mar 2005). Проверено 12 августа 2009. [www.webcitation.org/61G4nciiK Архивировано из первоисточника 28 августа 2011].

Литература

  • Лайза Криспин, Джанет Грегори. Гибкое тестирование: практическое руководство для тестировщиков ПО и гибких команд = Agile Testing: A Practical Guide for Testers and Agile Teams. — М.: «Вильямс», 2010. — 464 с. — (Addison-Wesley Signature Series). — 1000 экз. — ISBN 978-5-8459-1625-9.
  • Кент Бек. Экстремальное программирование: разработка через тестирование. — «Питер», 2003. ISBN 5-8046-0051-6, ISBN 0-321-14653-0

Отрывок, характеризующий Разработка через тестирование

– А помнишь, мы говорили с тобой про игру… дурак, кто на счастье хочет играть; играть надо наверное, а я хочу попробовать.
«Попробовать на счастие, или наверное?» подумал Ростов.
– Да и лучше не играй, – прибавил он, и треснув разорванной колодой, прибавил: – Банк, господа!
Придвинув вперед деньги, Долохов приготовился метать. Ростов сел подле него и сначала не играл. Долохов взглядывал на него.
– Что ж не играешь? – сказал Долохов. И странно, Николай почувствовал необходимость взять карту, поставить на нее незначительный куш и начать игру.
– Со мной денег нет, – сказал Ростов.
– Поверю!
Ростов поставил 5 рублей на карту и проиграл, поставил еще и опять проиграл. Долохов убил, т. е. выиграл десять карт сряду у Ростова.
– Господа, – сказал он, прометав несколько времени, – прошу класть деньги на карты, а то я могу спутаться в счетах.
Один из игроков сказал, что, он надеется, ему можно поверить.
– Поверить можно, но боюсь спутаться; прошу класть деньги на карты, – отвечал Долохов. – Ты не стесняйся, мы с тобой сочтемся, – прибавил он Ростову.
Игра продолжалась: лакей, не переставая, разносил шампанское.
Все карты Ростова бились, и на него было написано до 800 т рублей. Он надписал было над одной картой 800 т рублей, но в то время, как ему подавали шампанское, он раздумал и написал опять обыкновенный куш, двадцать рублей.
– Оставь, – сказал Долохов, хотя он, казалось, и не смотрел на Ростова, – скорее отыграешься. Другим даю, а тебе бью. Или ты меня боишься? – повторил он.
Ростов повиновался, оставил написанные 800 и поставил семерку червей с оторванным уголком, которую он поднял с земли. Он хорошо ее после помнил. Он поставил семерку червей, надписав над ней отломанным мелком 800, круглыми, прямыми цифрами; выпил поданный стакан согревшегося шампанского, улыбнулся на слова Долохова, и с замиранием сердца ожидая семерки, стал смотреть на руки Долохова, державшего колоду. Выигрыш или проигрыш этой семерки червей означал многое для Ростова. В Воскресенье на прошлой неделе граф Илья Андреич дал своему сыну 2 000 рублей, и он, никогда не любивший говорить о денежных затруднениях, сказал ему, что деньги эти были последние до мая, и что потому он просил сына быть на этот раз поэкономнее. Николай сказал, что ему и это слишком много, и что он дает честное слово не брать больше денег до весны. Теперь из этих денег оставалось 1 200 рублей. Стало быть, семерка червей означала не только проигрыш 1 600 рублей, но и необходимость изменения данному слову. Он с замиранием сердца смотрел на руки Долохова и думал: «Ну, скорей, дай мне эту карту, и я беру фуражку, уезжаю домой ужинать с Денисовым, Наташей и Соней, и уж верно никогда в руках моих не будет карты». В эту минуту домашняя жизнь его, шуточки с Петей, разговоры с Соней, дуэты с Наташей, пикет с отцом и даже спокойная постель в Поварском доме, с такою силою, ясностью и прелестью представились ему, как будто всё это было давно прошедшее, потерянное и неоцененное счастье. Он не мог допустить, чтобы глупая случайность, заставив семерку лечь прежде на право, чем на лево, могла бы лишить его всего этого вновь понятого, вновь освещенного счастья и повергнуть его в пучину еще неиспытанного и неопределенного несчастия. Это не могло быть, но он всё таки ожидал с замиранием движения рук Долохова. Ширококостые, красноватые руки эти с волосами, видневшимися из под рубашки, положили колоду карт, и взялись за подаваемый стакан и трубку.
– Так ты не боишься со мной играть? – повторил Долохов, и, как будто для того, чтобы рассказать веселую историю, он положил карты, опрокинулся на спинку стула и медлительно с улыбкой стал рассказывать:
– Да, господа, мне говорили, что в Москве распущен слух, будто я шулер, поэтому советую вам быть со мной осторожнее.
– Ну, мечи же! – сказал Ростов.
– Ох, московские тетушки! – сказал Долохов и с улыбкой взялся за карты.
– Ааах! – чуть не крикнул Ростов, поднимая обе руки к волосам. Семерка, которая была нужна ему, уже лежала вверху, первой картой в колоде. Он проиграл больше того, что мог заплатить.
– Однако ты не зарывайся, – сказал Долохов, мельком взглянув на Ростова, и продолжая метать.


Через полтора часа времени большинство игроков уже шутя смотрели на свою собственную игру.
Вся игра сосредоточилась на одном Ростове. Вместо тысячи шестисот рублей за ним была записана длинная колонна цифр, которую он считал до десятой тысячи, но которая теперь, как он смутно предполагал, возвысилась уже до пятнадцати тысяч. В сущности запись уже превышала двадцать тысяч рублей. Долохов уже не слушал и не рассказывал историй; он следил за каждым движением рук Ростова и бегло оглядывал изредка свою запись за ним. Он решил продолжать игру до тех пор, пока запись эта не возрастет до сорока трех тысяч. Число это было им выбрано потому, что сорок три составляло сумму сложенных его годов с годами Сони. Ростов, опершись головою на обе руки, сидел перед исписанным, залитым вином, заваленным картами столом. Одно мучительное впечатление не оставляло его: эти ширококостые, красноватые руки с волосами, видневшимися из под рубашки, эти руки, которые он любил и ненавидел, держали его в своей власти.
«Шестьсот рублей, туз, угол, девятка… отыграться невозможно!… И как бы весело было дома… Валет на пе… это не может быть!… И зачем же он это делает со мной?…» думал и вспоминал Ростов. Иногда он ставил большую карту; но Долохов отказывался бить её, и сам назначал куш. Николай покорялся ему, и то молился Богу, как он молился на поле сражения на Амштетенском мосту; то загадывал, что та карта, которая первая попадется ему в руку из кучи изогнутых карт под столом, та спасет его; то рассчитывал, сколько было шнурков на его куртке и с столькими же очками карту пытался ставить на весь проигрыш, то за помощью оглядывался на других играющих, то вглядывался в холодное теперь лицо Долохова, и старался проникнуть, что в нем делалось.
«Ведь он знает, что значит для меня этот проигрыш. Не может же он желать моей погибели? Ведь он друг был мне. Ведь я его любил… Но и он не виноват; что ж ему делать, когда ему везет счастие? И я не виноват, говорил он сам себе. Я ничего не сделал дурного. Разве я убил кого нибудь, оскорбил, пожелал зла? За что же такое ужасное несчастие? И когда оно началось? Еще так недавно я подходил к этому столу с мыслью выиграть сто рублей, купить мама к именинам эту шкатулку и ехать домой. Я так был счастлив, так свободен, весел! И я не понимал тогда, как я был счастлив! Когда же это кончилось, и когда началось это новое, ужасное состояние? Чем ознаменовалась эта перемена? Я всё так же сидел на этом месте, у этого стола, и так же выбирал и выдвигал карты, и смотрел на эти ширококостые, ловкие руки. Когда же это совершилось, и что такое совершилось? Я здоров, силен и всё тот же, и всё на том же месте. Нет, это не может быть! Верно всё это ничем не кончится».
Он был красен, весь в поту, несмотря на то, что в комнате не было жарко. И лицо его было страшно и жалко, особенно по бессильному желанию казаться спокойным.
Запись дошла до рокового числа сорока трех тысяч. Ростов приготовил карту, которая должна была итти углом от трех тысяч рублей, только что данных ему, когда Долохов, стукнув колодой, отложил ее и, взяв мел, начал быстро своим четким, крепким почерком, ломая мелок, подводить итог записи Ростова.
– Ужинать, ужинать пора! Вот и цыгане! – Действительно с своим цыганским акцентом уж входили с холода и говорили что то какие то черные мужчины и женщины. Николай понимал, что всё было кончено; но он равнодушным голосом сказал:
– Что же, не будешь еще? А у меня славная карточка приготовлена. – Как будто более всего его интересовало веселье самой игры.
«Всё кончено, я пропал! думал он. Теперь пуля в лоб – одно остается», и вместе с тем он сказал веселым голосом:
– Ну, еще одну карточку.
– Хорошо, – отвечал Долохов, окончив итог, – хорошо! 21 рубль идет, – сказал он, указывая на цифру 21, рознившую ровный счет 43 тысяч, и взяв колоду, приготовился метать. Ростов покорно отогнул угол и вместо приготовленных 6.000, старательно написал 21.
– Это мне всё равно, – сказал он, – мне только интересно знать, убьешь ты, или дашь мне эту десятку.
Долохов серьезно стал метать. О, как ненавидел Ростов в эту минуту эти руки, красноватые с короткими пальцами и с волосами, видневшимися из под рубашки, имевшие его в своей власти… Десятка была дана.
– За вами 43 тысячи, граф, – сказал Долохов и потягиваясь встал из за стола. – А устаешь однако так долго сидеть, – сказал он.
– Да, и я тоже устал, – сказал Ростов.
Долохов, как будто напоминая ему, что ему неприлично было шутить, перебил его: Когда прикажете получить деньги, граф?
Ростов вспыхнув, вызвал Долохова в другую комнату.
– Я не могу вдруг заплатить всё, ты возьмешь вексель, – сказал он.
– Послушай, Ростов, – сказал Долохов, ясно улыбаясь и глядя в глаза Николаю, – ты знаешь поговорку: «Счастлив в любви, несчастлив в картах». Кузина твоя влюблена в тебя. Я знаю.
«О! это ужасно чувствовать себя так во власти этого человека», – думал Ростов. Ростов понимал, какой удар он нанесет отцу, матери объявлением этого проигрыша; он понимал, какое бы было счастье избавиться от всего этого, и понимал, что Долохов знает, что может избавить его от этого стыда и горя, и теперь хочет еще играть с ним, как кошка с мышью.
– Твоя кузина… – хотел сказать Долохов; но Николай перебил его.
– Моя кузина тут ни при чем, и о ней говорить нечего! – крикнул он с бешенством.
– Так когда получить? – спросил Долохов.
– Завтра, – сказал Ростов, и вышел из комнаты.


Сказать «завтра» и выдержать тон приличия было не трудно; но приехать одному домой, увидать сестер, брата, мать, отца, признаваться и просить денег, на которые не имеешь права после данного честного слова, было ужасно.
Дома еще не спали. Молодежь дома Ростовых, воротившись из театра, поужинав, сидела у клавикорд. Как только Николай вошел в залу, его охватила та любовная, поэтическая атмосфера, которая царствовала в эту зиму в их доме и которая теперь, после предложения Долохова и бала Иогеля, казалось, еще более сгустилась, как воздух перед грозой, над Соней и Наташей. Соня и Наташа в голубых платьях, в которых они были в театре, хорошенькие и знающие это, счастливые, улыбаясь, стояли у клавикорд. Вера с Шиншиным играла в шахматы в гостиной. Старая графиня, ожидая сына и мужа, раскладывала пасьянс с старушкой дворянкой, жившей у них в доме. Денисов с блестящими глазами и взъерошенными волосами сидел, откинув ножку назад, у клавикорд, и хлопая по ним своими коротенькими пальцами, брал аккорды, и закатывая глаза, своим маленьким, хриплым, но верным голосом, пел сочиненное им стихотворение «Волшебница», к которому он пытался найти музыку.
Волшебница, скажи, какая сила
Влечет меня к покинутым струнам;
Какой огонь ты в сердце заронила,
Какой восторг разлился по перстам!
Пел он страстным голосом, блестя на испуганную и счастливую Наташу своими агатовыми, черными глазами.
– Прекрасно! отлично! – кричала Наташа. – Еще другой куплет, – говорила она, не замечая Николая.
«У них всё то же» – подумал Николай, заглядывая в гостиную, где он увидал Веру и мать с старушкой.
– А! вот и Николенька! – Наташа подбежала к нему.
– Папенька дома? – спросил он.
– Как я рада, что ты приехал! – не отвечая, сказала Наташа, – нам так весело. Василий Дмитрич остался для меня еще день, ты знаешь?
– Нет, еще не приезжал папа, – сказала Соня.
– Коко, ты приехал, поди ко мне, дружок! – сказал голос графини из гостиной. Николай подошел к матери, поцеловал ее руку и, молча подсев к ее столу, стал смотреть на ее руки, раскладывавшие карты. Из залы всё слышались смех и веселые голоса, уговаривавшие Наташу.
– Ну, хорошо, хорошо, – закричал Денисов, – теперь нечего отговариваться, за вами barcarolla, умоляю вас.
Графиня оглянулась на молчаливого сына.
– Что с тобой? – спросила мать у Николая.
– Ах, ничего, – сказал он, как будто ему уже надоел этот всё один и тот же вопрос.
– Папенька скоро приедет?
– Я думаю.
«У них всё то же. Они ничего не знают! Куда мне деваться?», подумал Николай и пошел опять в залу, где стояли клавикорды.
Соня сидела за клавикордами и играла прелюдию той баркароллы, которую особенно любил Денисов. Наташа собиралась петь. Денисов восторженными глазами смотрел на нее.
Николай стал ходить взад и вперед по комнате.
«И вот охота заставлять ее петь? – что она может петь? И ничего тут нет веселого», думал Николай.
Соня взяла первый аккорд прелюдии.
«Боже мой, я погибший, я бесчестный человек. Пулю в лоб, одно, что остается, а не петь, подумал он. Уйти? но куда же? всё равно, пускай поют!»
Николай мрачно, продолжая ходить по комнате, взглядывал на Денисова и девочек, избегая их взглядов.
«Николенька, что с вами?» – спросил взгляд Сони, устремленный на него. Она тотчас увидала, что что нибудь случилось с ним.
Николай отвернулся от нее. Наташа с своею чуткостью тоже мгновенно заметила состояние своего брата. Она заметила его, но ей самой так было весело в ту минуту, так далека она была от горя, грусти, упреков, что она (как это часто бывает с молодыми людьми) нарочно обманула себя. Нет, мне слишком весело теперь, чтобы портить свое веселье сочувствием чужому горю, почувствовала она, и сказала себе:
«Нет, я верно ошибаюсь, он должен быть весел так же, как и я». Ну, Соня, – сказала она и вышла на самую середину залы, где по ее мнению лучше всего был резонанс. Приподняв голову, опустив безжизненно повисшие руки, как это делают танцовщицы, Наташа, энергическим движением переступая с каблучка на цыпочку, прошлась по середине комнаты и остановилась.
«Вот она я!» как будто говорила она, отвечая на восторженный взгляд Денисова, следившего за ней.
«И чему она радуется! – подумал Николай, глядя на сестру. И как ей не скучно и не совестно!» Наташа взяла первую ноту, горло ее расширилось, грудь выпрямилась, глаза приняли серьезное выражение. Она не думала ни о ком, ни о чем в эту минуту, и из в улыбку сложенного рта полились звуки, те звуки, которые может производить в те же промежутки времени и в те же интервалы всякий, но которые тысячу раз оставляют вас холодным, в тысячу первый раз заставляют вас содрогаться и плакать.
Наташа в эту зиму в первый раз начала серьезно петь и в особенности оттого, что Денисов восторгался ее пением. Она пела теперь не по детски, уж не было в ее пеньи этой комической, ребяческой старательности, которая была в ней прежде; но она пела еще не хорошо, как говорили все знатоки судьи, которые ее слушали. «Не обработан, но прекрасный голос, надо обработать», говорили все. Но говорили это обыкновенно уже гораздо после того, как замолкал ее голос. В то же время, когда звучал этот необработанный голос с неправильными придыханиями и с усилиями переходов, даже знатоки судьи ничего не говорили, и только наслаждались этим необработанным голосом и только желали еще раз услыхать его. В голосе ее была та девственная нетронутость, то незнание своих сил и та необработанная еще бархатность, которые так соединялись с недостатками искусства пенья, что, казалось, нельзя было ничего изменить в этом голосе, не испортив его.
«Что ж это такое? – подумал Николай, услыхав ее голос и широко раскрывая глаза. – Что с ней сделалось? Как она поет нынче?» – подумал он. И вдруг весь мир для него сосредоточился в ожидании следующей ноты, следующей фразы, и всё в мире сделалось разделенным на три темпа: «Oh mio crudele affetto… [О моя жестокая любовь…] Раз, два, три… раз, два… три… раз… Oh mio crudele affetto… Раз, два, три… раз. Эх, жизнь наша дурацкая! – думал Николай. Всё это, и несчастье, и деньги, и Долохов, и злоба, и честь – всё это вздор… а вот оно настоящее… Hy, Наташа, ну, голубчик! ну матушка!… как она этот si возьмет? взяла! слава Богу!» – и он, сам не замечая того, что он поет, чтобы усилить этот si, взял втору в терцию высокой ноты. «Боже мой! как хорошо! Неужели это я взял? как счастливо!» подумал он.
О! как задрожала эта терция, и как тронулось что то лучшее, что было в душе Ростова. И это что то было независимо от всего в мире, и выше всего в мире. Какие тут проигрыши, и Долоховы, и честное слово!… Всё вздор! Можно зарезать, украсть и всё таки быть счастливым…


Давно уже Ростов не испытывал такого наслаждения от музыки, как в этот день. Но как только Наташа кончила свою баркароллу, действительность опять вспомнилась ему. Он, ничего не сказав, вышел и пошел вниз в свою комнату. Через четверть часа старый граф, веселый и довольный, приехал из клуба. Николай, услыхав его приезд, пошел к нему.
– Ну что, повеселился? – сказал Илья Андреич, радостно и гордо улыбаясь на своего сына. Николай хотел сказать, что «да», но не мог: он чуть было не зарыдал. Граф раскуривал трубку и не заметил состояния сына.
«Эх, неизбежно!» – подумал Николай в первый и последний раз. И вдруг самым небрежным тоном, таким, что он сам себе гадок казался, как будто он просил экипажа съездить в город, он сказал отцу.
– Папа, а я к вам за делом пришел. Я было и забыл. Мне денег нужно.
– Вот как, – сказал отец, находившийся в особенно веселом духе. – Я тебе говорил, что не достанет. Много ли?
– Очень много, – краснея и с глупой, небрежной улыбкой, которую он долго потом не мог себе простить, сказал Николай. – Я немного проиграл, т. е. много даже, очень много, 43 тысячи.
– Что? Кому?… Шутишь! – крикнул граф, вдруг апоплексически краснея шеей и затылком, как краснеют старые люди.
– Я обещал заплатить завтра, – сказал Николай.
– Ну!… – сказал старый граф, разводя руками и бессильно опустился на диван.
– Что же делать! С кем это не случалось! – сказал сын развязным, смелым тоном, тогда как в душе своей он считал себя негодяем, подлецом, который целой жизнью не мог искупить своего преступления. Ему хотелось бы целовать руки своего отца, на коленях просить его прощения, а он небрежным и даже грубым тоном говорил, что это со всяким случается.
Граф Илья Андреич опустил глаза, услыхав эти слова сына и заторопился, отыскивая что то.
– Да, да, – проговорил он, – трудно, я боюсь, трудно достать…с кем не бывало! да, с кем не бывало… – И граф мельком взглянул в лицо сыну и пошел вон из комнаты… Николай готовился на отпор, но никак не ожидал этого.
– Папенька! па…пенька! – закричал он ему вслед, рыдая; простите меня! – И, схватив руку отца, он прижался к ней губами и заплакал.

В то время, как отец объяснялся с сыном, у матери с дочерью происходило не менее важное объяснение. Наташа взволнованная прибежала к матери.
– Мама!… Мама!… он мне сделал…
– Что сделал?
– Сделал, сделал предложение. Мама! Мама! – кричала она. Графиня не верила своим ушам. Денисов сделал предложение. Кому? Этой крошечной девочке Наташе, которая еще недавно играла в куклы и теперь еще брала уроки.
– Наташа, полно, глупости! – сказала она, еще надеясь, что это была шутка.
– Ну вот, глупости! – Я вам дело говорю, – сердито сказала Наташа. – Я пришла спросить, что делать, а вы мне говорите: «глупости»…
Графиня пожала плечами.
– Ежели правда, что мосьё Денисов сделал тебе предложение, то скажи ему, что он дурак, вот и всё.
– Нет, он не дурак, – обиженно и серьезно сказала Наташа.
– Ну так что ж ты хочешь? Вы нынче ведь все влюблены. Ну, влюблена, так выходи за него замуж! – сердито смеясь, проговорила графиня. – С Богом!
– Нет, мама, я не влюблена в него, должно быть не влюблена в него.
– Ну, так так и скажи ему.
– Мама, вы сердитесь? Вы не сердитесь, голубушка, ну в чем же я виновата?
– Нет, да что же, мой друг? Хочешь, я пойду скажу ему, – сказала графиня, улыбаясь.
– Нет, я сама, только научите. Вам всё легко, – прибавила она, отвечая на ее улыбку. – А коли бы видели вы, как он мне это сказал! Ведь я знаю, что он не хотел этого сказать, да уж нечаянно сказал.
– Ну всё таки надо отказать.
– Нет, не надо. Мне так его жалко! Он такой милый.
– Ну, так прими предложение. И то пора замуж итти, – сердито и насмешливо сказала мать.
– Нет, мама, мне так жалко его. Я не знаю, как я скажу.
– Да тебе и нечего говорить, я сама скажу, – сказала графиня, возмущенная тем, что осмелились смотреть, как на большую, на эту маленькую Наташу.
– Нет, ни за что, я сама, а вы слушайте у двери, – и Наташа побежала через гостиную в залу, где на том же стуле, у клавикорд, закрыв лицо руками, сидел Денисов. Он вскочил на звук ее легких шагов.
– Натали, – сказал он, быстрыми шагами подходя к ней, – решайте мою судьбу. Она в ваших руках!
– Василий Дмитрич, мне вас так жалко!… Нет, но вы такой славный… но не надо… это… а так я вас всегда буду любить.
Денисов нагнулся над ее рукою, и она услыхала странные, непонятные для нее звуки. Она поцеловала его в черную, спутанную, курчавую голову. В это время послышался поспешный шум платья графини. Она подошла к ним.
– Василий Дмитрич, я благодарю вас за честь, – сказала графиня смущенным голосом, но который казался строгим Денисову, – но моя дочь так молода, и я думала, что вы, как друг моего сына, обратитесь прежде ко мне. В таком случае вы не поставили бы меня в необходимость отказа.
– Г'афиня, – сказал Денисов с опущенными глазами и виноватым видом, хотел сказать что то еще и запнулся.
Наташа не могла спокойно видеть его таким жалким. Она начала громко всхлипывать.
– Г'афиня, я виноват перед вами, – продолжал Денисов прерывающимся голосом, – но знайте, что я так боготво'ю вашу дочь и всё ваше семейство, что две жизни отдам… – Он посмотрел на графиню и, заметив ее строгое лицо… – Ну п'ощайте, г'афиня, – сказал он, поцеловал ее руку и, не взглянув на Наташу, быстрыми, решительными шагами вышел из комнаты.

На другой день Ростов проводил Денисова, который не хотел более ни одного дня оставаться в Москве. Денисова провожали у цыган все его московские приятели, и он не помнил, как его уложили в сани и как везли первые три станции.