Thursday, October 30, 2008

Архитектура StackOverflow.com

Сегодня по дороге на работу/с работы прослушал подкаст Hanseminutes #134 о том, как Jeff Atwood, Joel Spolsky и его команда создали сайт StackOverflow.com. Пара слов о сайте: это с одной стороны типичный Q&A сайт-сообщество, а с другой – немного другая песня. Джефф и Джоэль провели достаточно серьезный анализ похожих сайтов и вроде как постарались сделать максимально удобный и продвинутый ресурс, ориентированный на IT-специалистов. Не могу судить о том, успешен он или нет, но вроде бы за месяц у них уже много пользователей.

В этом подкасте не было бы ничего особенного, если бы не техническое обсуждение особенностей реализации сайта. Во-первых, сайт написан с использованием ASP.NET MVC, что уже примечательно для меня, т.к. я последнюю неделю занимался его изучением. И это несмотря на то, что ASP.NET MVC еще только недавно вышел в бете. То есть это один из первых достаточно популярных сайтов, которые используют эту технологию. Во-вторых, несмотря на то, что это сайт, предполагающий высокую нагрузку, они использовали Linq to SQL в качестве ORM. Также они сами признаются, что им пришлось напрячься, чтобы реализовать output-кеширование разных разделов страницы (некоторые куски страницы обновляются раз в минуту, некоторые – чаще). Еще у них были большие проблемы с локами и дедлоками в MS SQL сервере и они были вынуждены перейти на read committed snapshot”-транзакции (как это сделать в Linq to SQL и Entity Framework, можно почитать здесь). И это еще не все. Они использовали GZIP-сжатие страниц, причем не только для уменьшения размера страницы, но и для уменьшения размера страницы в кеше. И им действительно удалось добиться быстрой работы сайта на серьезных нагрузках. Можете проверить сами.

Однако это была лишь присказка :) Сказка начинается теперь. Угадайте, какое у них железо, сколько у них серверов? 4? 8? Больше? ОДИН! Один сервер, на котором крутятся и web-приложение, и база данных. 8-ядерный процессор, 4 Гб ОЗУ, 64-битная архитектура (процессор, ОС, .NET Framework, MS SQL сервер). Ничего особенного. В ответ на это Скотт говорит что-то вроде «это же не best practice, как вообще можно так делать?». И ему отвечают: «ну, мы перейдем со временем на ДВА сервера... когда будет нужно :)». И в конце добавляют контрольный выстрел в голову: их build-сервер, построенный на CC.NET, работает на ТОМ же production-сервере. Это какой-то ужас с точки зрения развертывания приложений, но это работает! :)

Со всем этим они умудряются делать ежедневные релизы новой версии, прогоняя ее на unit-тестах при каждом билде (обычный CI). Это значит, что у них получается нормальная стабильная версия, готовая к выходу в люди, каждый день. Думаю, нам всем есть чему поучиться в плане написания качественного софта, не говоря уже про performance на таком железе :) Да, нагрузка у них пока еще не слишком большая, но все же уже не детская. Я знаю продукты, на которых сайт лежал уже на десятке пользователей :)

А вы говорите, различные facebook’и работают на десятках, а то и сотнях серверов? Ну-ну :)

PS. Да, там уже доступна вторая серия этого общения. Еще не успел послушать, но если будет что-то интересное, сделаю update.

Upd. Послушал вторую часть, там все время идет обсуждение безопасности решения с одним сервером для приложения и базы данных. Скотт, который долгое время работал в банковской сфере, пытается убедить ребят, что их решение несекьюрно, на что те вроде как соглашаются. Рекомендую к прослушиванию лишь тем, кому вопросы безопасности интересны.

Upd2. Если кому-то интересно подробнее почитать про то, как рождался сайт StackOverflow.com, кому пришла в голову идея, сколько людей и как долго его писали, какие есть идеи его монетизации и сколько стоит обслуживание сайта в месяц - Джоэль рассказывает об этом в своей статье "How Hard Could It Be?: The Unproven Path"

Saturday, October 25, 2008

IT-отрасль и финансовый кризис

Сейчас о финансовом кризисе не говорит и не пишет разве что ленивый. Мы тут с другом тоже на досуге поразмыслили над тем, что несет финансовый кризис индустрии разработки ПО в целом и аутсорсингу ПО в частности.

Disclaimer. Эти размышления не претендуют на истину в последней инстанции, более того, они касаются в основном рынка разработки ПО города Харькова, хотя, думаю, их можно аппроксимировать как минимум на всю Украину, а, возможно, даже и на все постсоветское пространство.

Итак, вернемся к теме. С большой долей вероятности можно считать, что «золотой век русского программиста» если не закончился, то остановился. Я не скажу за всю Одессу, но в Харькове уже сейчас заметны некоторые отрицательные тенденции. Часть клиентов останавливает рост своих команд, некоторые компании, которые раньше брали людей на работу толпами, уже в открытую говорят о возможных сокращениях штата.

Причины и следствия

Попробуем проанализировать ситуацию. Финансовый кризис, прежде всего, вызван кризисом инвестиций. На западе очень частой является ситуация, когда у одних людей (разработчиков) есть идея стартапа, а у других – деньги (венчурные капиталисты и другие инвесторы). Раньше инвесторы позволяли себе роскошь выделять средства на рискованные проекты (даже после краха доткомов), теперь же с этим будет туго. Если вы заняты разработкой подобного стартапа, будьте готовы к тому, что на проекте может быть урезан бюджет или он может быть вообще закрыт (это, в частности, про меня). В тех же ситуациях, когда компания заказывает проект для себя, для автоматизации своего производства или дальнейшей продажи, можно ожидать всякого. При отсутствии финансов компании в первую очередь урезают всякие дополнительные расходы, к которым зачастую относят и разработку ПО, если, конечно, компания не зарабатывает продажей этого ПО. Немаловажно здесь и состояние компании-клиента и область ее бизнеса. Некоторые отрасли будут более подвержены кризису, чем другие. То есть вашему проекту может повезти, а может и не очень. В то же время, финансовый кризис может подстегнуть рост аутсорсинга, потому что западные и дальневосточные компании будут вынуждены уменьшать расходы, как и 8 лет назад, когда крах доткомов и 11 сентября дали толчок быстрому развитию аутсорсинга. Подробнее об этом можно почитать здесь и здесь.

Чем это грозит простым труженикам клавиатуры и мышки?

Теперь посмотрим на то, чем это грозит всем нам. На мой взгляд, потенциально возможны как минимум 2 этапа перед тем, как ситуация снова вернется в старую колею: 1) остановка развития и 2) деградация. Заденут ли нас оба этапа или ситуация успеет нормализироваться до наступления второго – это очень интересный вопрос.

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

Второй этап будет намного хуже, чем первый. И начнется он, если, не дай Бог, клиенты начнут банкротиться или сворачивать проекты. Судя по тому, что аналитики прогнозируют пик кризиса на начало 2009 года, это может начаться именно тогда. А может и не начаться – я не специалист, чтобы ответить на этот вопрос. Однако, чисто гипотетически, ЕСЛИ такое произойдет, то всем нам это грозит двумя вещами: 1) начнутся массовые увольнения вследствие закрытия целых проектов, которые увеличат предложение на рынке, при этом спрос будет почти равен нулю, 2) будут понижения зарплат, если уж не для текущих сотрудников, то, по крайней мере, для тех, кого принимают на работу. Средние зарплаты начнут падать.

Так что, о постоянных существенных повышениях зарплат (за 4 года, которые я слежу за рынком, средние зарплаты в аутсорсовых компаниях повысились в 4-8 раза) и легких переходах с места на место можно забыть. Кроме того, возможно обострение противоречий между сотрудниками компаний и их владельцами. Понять можно и тех, и других: обеим сторонам будут нужны деньги, чтобы выжить. Вот только для первых это означает увеличение зарплаты, а для вторых - уменьшение расходов, в том числе и на зарплату. Если вам повезло, и вы нашли хорошее место работы с достойной зарплатой – good for you. Возможно, нас всех пронесет на этот раз, а возможно, и нет, и мы получим еще один 2000-2002 год, когда зарплаты держались на уровне 200-400 долларов, а новых сотрудников предпочитали не нанимать.

Как пережить смутные времена?

Ответ прост – быть действительно эффективным, полезным и перспективным на своем месте работы. Да, это клише, которое подходит и для не-кризиса. Однако сейчас это клише приобретает другой оттенок.

Быть эффективным и полезным – это значит не просто делать свою работу, но делать ее быстро, качественно, ответственно и, что самое главное, добиваться положительного результата. Про эффективность хорошо написал Сергей Розовик. Если вы привыкли часть рабочего времени посвящать социальным сетям или башоргу – пора отучиться от этой вредной привычки. Если вы привыкли работать расслабленно, спустя рукава – почитайте про «7 навыков высокоэффективных людей», статьи о лайфхакинге и других способах повышения личной производительности и эффективности. Если у вас есть проблемы на проекте – надо задуматься об их причинах и устранить их.

Быть перспективным – это значит не просто обладать потенциалом, но использовать и повышать его. Если вы уже забыли, когда последний раз читали книги или статьи по программированию (менеджменту, тестированию, администрированию, нужное подчеркнуть) – впору заняться самообразованием. IT – это не та отрасль, где можно выйти из университета с полученным багажом знаний и годами его использовать в работе, здесь нужно развиваться. Почитайте про новые технологии, языки программирования, подходы к разработке и методологии ведения проектов. Даже если вам это не понадобиться сегодня, вам это может срочно понадобиться завтра при приеме на новую работу.

Ну, и последний совет. Финансовый кризис ударит по нам не только со стороны работы, но и стороны нашей повседневной жизни. Проанализируйте ситуацию и советы аналитиков о том, что нужно делать с лежащими на депозитах деньгами, счетами, кредитами. Запасайтесь картошкой :) Отучите себя наконец-то брать потребительские кредиты! А если нужен кредит на машину/квартиру, то лучше повременить. Еще о стратегиях выживания во время кризиса можно почитать у Макса Крайнова, а можно найти и другие – благо их сейчас полно.

Какие будут результаты

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

На локальном же уровне в нашей отрасли наверняка произойдут следующие вещи:

1) Произойдет естественный отбор, количество компаний на рынке сократиться, исчезнут самые слабые и неприспособленные

2) Выжившие компании сбросят лишний вес, который им мешал развиваться дальше, станут более гибкими и устойчивыми (почитайте, например, книгу Луиса Герстнера «Кто сказал что слоны не умеют танцевать?» о том, как IBM вышла из крутого пике в начале 90-х годов)

3) Рынок IT-специалистов стабилизируется, зарплаты перестанут расти неимоверными скачками, а сами специалисты станут умнее и профессиональнее.

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

Еще немного о кризисе понятными словами можно прочитать здесь:

Понятно о кризисе
Экономический кризис на пальцах
Прививка от идиотизма

Еще немного о пользе unit-тестирования

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

1. Unit-тесты позволяют найти баги в существующем коде

Пример. Следуя совету в первую очередь писать тесты на критический функционал (во-первых, его меньше, во-вторых, если он ломается, то ломается с большим грохотом), мы решили покрыть тестами систему прав и некоторый кусок бизнес-логики, реализующий сложные вычисления по иерархиям объектов и их связям с другими иерархиями. Казалось бы, проекту уже стукнул годик, этому коду – более полугода, была уже куча итераций с тестированием, код должен работать правильно! Ага, щаз. При помощи unit-тестов было найдено полдюжины багов в логике вычисления прав (штуки три – вообще критических) и чуть меньше в вычислениях по иерархиям.

2. Зачастую unit-тесты позволяют быстрее и проще тестировать код, чем это можно сделать через UI

Столкнувшись с ситуацией, описанной в предыдущем примере, я начал задавать себе вопрос: почему баги не были найдены раньше, и получил достаточно простой ответ: сделать это через UI очень сложно. Наши QA, как и программисты, которые писали этот код, не виноваты – просто есть определенная степень сложности в системе, после которой и первые, и вторые просто физически не могут проверить все варианты в установленные сжатые сроки. Например, система прав учитывает с одной стороны иерархию пользователей и ролей, а с другой – иерархию объектов. Обе иерархии имеют свои правила наследования прав, которые влияют на получение окончательного результата. Вычисления очень похожи: они учитывают как иерархические связи внутри иерархии, так и связи с другими иерархиями. При этом через UI это все просто невозможно протестировать полностью в резонное время! Вот здесь-то на помощь и приходят unit-тесты. Быстро воссоздав иерархии объектов и связи между ними в тестах, мы легко нашли и обезвредили толпу багов.

3. Unit-тесты позволяют почувствовать душок, исходящий от вашего кода

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

Я не буду уже писать о том, как написанные unit-тесты помогали нам после изменения существующего кода (допустим, добавления кеширования) – здесь их польза и так ясна как день :)

Sunday, October 19, 2008

Happy Birthday!

В ежедневной рутине прошедшей недели как-то совсем пропустил момент, что у данного блога 15 октября был день рождения. Да, нам уже годик, так что принимаются поздравления :)

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

За этот год сформировалась определенная тематика блога: это не чистый технический блог, но в то же время и не дневник. Я стараюсь писать около 80% постов об IT и программировании, так как это основное назначение блога, но в то же время разбавляю эти сообщения рассказами о путешествиях и походах, в которых я побывал, а также фотографиями разной направленности. Думаю, такой подход имеет право на жизнь. Кроме того, я стараюсь писать о том, с чем сталкивался сам, делиться своим опытом. Принципиально стараюсь не писать сообщений типа «Сегодня вышла технология такая-то, в ней есть такой вот переведенный мной с MSDN список фич».

Также где-то около недели назад я настроил Google Analytics для блога (сделать это можно для любого сайта, а как это сделать для blogspot’а, можно прочитать здесь). Жаль, конечно, что я этого не сделал раньше (урок №1), но все же уже даже по данным за эту неделю можно сделать определенные выводы о том, кто посещает блог, откуда, зачем и в каких количествах.

Абсолютное большинство посетителей – пользователи из России и Украины, что понятно. За недельку несколько человек заглянули из Испании и Норвегии, но, скорее всего они испугались, закрыли окошко и пошли дальше :) Хотя один человек оставил комментарий на английском в теме об Entity Framework rollback, но я его увидел слишком поздно. Урок №2 – не забывайте настраивать оповещение о комментариях на почту, если не хотите пропустить что-то важное.

По данным Google Reader, на блог сейчас подписано около 20 человек, что не очень много, за неделю же пришло 60 уникальных пользователей. Еще один вывод: люди приходят на блог, но при этом редко добавляют его в ридеры. Так что если вы иногда читаете блог, но еще не добавили его в ридер – сделайте это, мне будет приятно :) Конечно, если он того стоит.

Дальше о браузерах. Думаю, поклонникам Firefox будет приятно узнать, что по данным моего блога, его используют больше 50% пользователей (ура, товарищи!), IE вместе с Оперой делят почетное второе место с 17%, а Хромом пользуются уже почти 9% (ага, попались, гуглолюбы :)). Есть даже 1% SeaMonkey (это еще что за зверь такой?), а вот Сафари пока не было (хотя что им делать на блоге, посвященном технологиям Microsoft).

Распределение по операционным системам очень простое: 96% за Windows, 4% пользуются Linux и Mac (причем, Firefox).

61% посетителей приходит на сайт из поисковиков (70% - Google, 30% - Yandex), 23% - с других сайтов (спасибо Паше Подлипенскому, Наде Плаховой и каким-то неизвестным блогам в Blogger), и 16% - напрямую вбивая адрес в поисковике.

Ну, и самое интересное – зачем же люди сюда идут? Судя по поисковым запросам, довольно много посетителей приходит, чтобы почитать про Entity Framework, второй по популярности темой оказались unit-тесты, что не может не радовать, далее с большим отставанием остальные темы. Понравилось, что люди ищут навыки программиста, mind maps, подкасты для программистов и даже слова для песни «Щедрик» :)

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

И напоследок небольшой хит-парад постов.

Самые обсуждаемые:
Entity Framework: Vote Of Confidence (8)
Оценка уровня программиста (8)
Entity Framework + NAnt - трудности с включением файлов модели в сборку (6)
Наш ответ Scott'у Hanselman'у (5)
Аутсорсинг ПО = утечка мозгов (5)
Планирование, учитывающее предыдущие результаты (5)

Полезные технические (с моей точки зрения):
Continuous Tech Development (полезно всем, кто хочет профессионально развиваться и в то же время тратить на это минимум свободного времени)
Оценка уровня программиста (о том, какие критерии оценки я вынес для себя)
Mind maps и анализ требований (mind maps – интересная техника, советую всем)
Entity Framework rollback: Часть 4. Пример приложения (советую все 4 части тем, кто хочет разобраться в том, как работает EF внутри)
OutOfMemoryException и как его побороть (многие друзья написали, что круто, но сложно :) – невзирая на это, советую всем, кто хочет разобраться с тем, как отлаживать сложные ситуации)
Введение в mock-объекты. Классификация (must-read для всех, кто хочет понять, что такое mock-объекты и как их правильно использовать)
Unit-тестирование для Entity Framework (название говорит само за себя)

Интересные нетехнические посты:
Хамар-Дабан, пик Черского (отчет о походе на пик Черского, что возле Байкала)
Байкал (описание Байкала)
Иркутск и панорамы из путешествия на Байкал (описание Иркутска и панорамы)
Путешествие «Щедрика» (о том, как малоизвестная украинская мелодия стала одной из самых популярных в мире, а мы об этом и не знаем)
Фильм "Бесценный доллар" (интересный, хотя и спорный фильм об экономике Штатов и мировой экономике)

Итак, итоги года подведены. Спасибо всем, кто читает этот блог! Если у вас есть советы, критика или комментарии по его улучшению – поделитесь со мной :) Я же, со своей стороны, постараюсь писать больше и интереснее.

Sunday, October 12, 2008

Unit-тестирование для Entity Framework

Как вы уже наверно догадались по тематике моих нескольких предыдущих постов, я сейчас активно занимаюсь изучением и внедрением unit-тестов на своем проекте. Сегодня я хотел бы поделиться решением одной из самых трудных задач, с которой мне пришлось столкнуться, а именно реализацией поддержки unit-тестирования в Entity Framework.

Если вы сейчас погуглите по этой теме, то найдете мало ответов на простой вопрос: как заставить unit-тесты работать с Entity Framework. Думаю, есть несколько вариантов решения, но я бы хотел поделиться нашим. Его преимущество в том, что он не использует базу. Можно долго спорить на тему того, как нужно тестировать Data Access Layer, чтобы код лез в базу или не лез туда. У варианта с использованием базы есть как свои достоинства, так и недостатки. Лично я считаю, что unit-тесты должны покрывать полностью лишь код DAL'а, если же вы хотите заодно проверять и базу – напишите небольшое количество integration-тестов, которые будут проверять соединение, а также какой-то минимальный набор CRUD-запросов, чтобы при случае найти ошибки и здесь. Мы же дальше будем рассматривать тестирование без базы данных.

Итак, в чем же, собственно, состоит проблема? Дело в том, что Entity Framework, к сожалению, проектировался не совсем для того, чтобы код, содержащий вызовы к нему, можно было легко протестировать – слишком уж завязаны сущности на контекст и слишком уж много функций контекст берет на себя (куда ж без этого):

  • сгенерированные ObjectQuery<T>-свойства для доступа к данным обращаются напрямую к базе данных
  • не поддерживает POCO (Plain Old CLR Objects), все объекты содержат navigation properties и Load-методы, которые также обращаются к базе
  • не поддерживает принцип Persistence Ignorance, то есть все объекты сами знают, как себя сохранять

Однако, несмотря на все это, Entity Framework обладает дополнительными полезными свойствами, которые нам помогут:

  • EF кеширует сущности в памяти, более того, позволяет работать с контекстом, как датасет: у сущностей есть состояния (unchanged, inserted, updated, deleted и др.), а также метод AcceptAllChanges, который переводит добавленные или измененные объекты в состояние unchanged
  • EF не поддерживает lazy loading, который бы мог привести к проблемам
  • контекст EF, основываясь на схеме модели, имеет достаточное количество информации о типах связей между сущностями, constraint'ах, not null-полях и т.д., чтобы автоматически проверять, все ли вы верно проинициализировали перед тем, как засылать сущность в базу данных, причем делает это даже когда вы не работаете с базой, а вызываете AcceptAllChanges()
  • внутренний API контекста достаточно открыт, чтобы самому производить доступ к закешированным сущностям, обходя стандартные ObjectQuery-свойства

Итак, как же нам нужно модифицировать наш код, чтобы он стал тестабельным?

  1. Прежде всего, для нашего же удобства нам стоит выделить код, работающий с IQueryable, ObjectQuery и IRelatedEnd.Load в отдельный слой – Data Access Layer. Не важно, как вы это реализуете, лишь бы у вас был контроль над теми местами, где идут запросы к EF. Если вы это уже сделали, good for you.
  2. Далее нужно перевести контекст в так называемый metadata-only режим, который исключает доступ к базе данных вообще. Перевод этот производится урезанием строки соединения до путей к метаданным и названия провайдера. То есть строку соединения с базой мы не пишем.
  3. Для тех случаев, когда мы работаем с unit-тестами, нужно заменить вызовы SaveChanges на AcceptAllChanges
  4. Для тех случаев, когда мы работаем с unit-тестами, нужно реализовать получение данных исключительно из ObjectStateManager, т.е. из памяти, а не из автосгенерированных ObjectQuery-свойств.
  5. Для тех случаев, когда мы работаем с unit-тестами, исключаем из кода любые вызовы IRelatedEnd.Load, то есть все обращения к Load-методу из navigation-свойств сущностей.
  6. Если был реализован lazy loading (через все те же IRelatedEnd.Load), необходимо его отключить.

Возникает вопрос: как ЭТО ВСЕ реализовать физически в коде? Не писать же отдельные методы доступа к данным для unit-тестов. Ответ прост: это можно реализовать при помощи Dependency Injection. То есть основная идея такова: нужно реализовать специальный интерфейс, содержащий методы GetEntities<T>, GetEntity<T> и ApplyPendingChanges, а также как минимум двух его наследников: одного для реального доступа к базе, другого – для работы с контекстом в памяти. Все, наши методы DAL, естественно, будут использовать именно эти методы, а вот какой объект будет инициализирован в DAL – это уже зависит от того, находимся мы в реальном приложении, или в режиме тестирования.

Я решил приготовить пример кода вместо того, чтобы делать еще один длиннющий пост с подробностями. Реализация достаточно проста, поэтому, думаю, кому нужно, те разберутся и без моей помощи :) В примере используется контекст на базе данных Northwind, в качестве unit-test framework'а я использовал NUnit. Если будут вопросы по коду – пишите в комментариях. Будет много вопросов – напишу отдельный пост с разъяснениями.

Собственно, пример реализации можно найти здесь:

Пример реализации поддержки unit-тестирования в Entity Framework

Удачи всем!

Upd. В ответ на справедливое замечание Миши Чалого о том, что в коде нифига не DI, изменил код, чтобы DI там было :) Кроме того, вынес знание об инициализации контекста и mock-обертку в проект unit-теста, где они и должны быть. Код стал более правильным, так что прошу скачивать и использовать вторую версию по той же ссылке.