Если под пунктом 2 вы подразумеваете «папку bin для каждого решения» - я вижу вашу точку зрения. Лично я бы просто добавил ссылку на каждый тестовый проект. Если, с другой стороны, вы действительно имеете в виду (1b) «не помещайте свои тесты в ту же сборку, что и ваш код», я от всего сердца согласен с ним и не согласен с вами. Ваши тесты должны отличаться от вашего производственного кода, чтобы улучшить ясность кода и его организацию. Хранение тестовых классов отдельно помогает следующему программисту понять это легче. Если вам нужен доступ к внутренним компонентам в ваших тестах - и вы можете это сделать, поскольку внутренние методы являются «открытыми» для сборки, вы можете использовать конструкцию InternalsVisibleTo в файле Assembly.cs.
Я бы тоже порекомендовал, чтобы в общем случае достаточно было модульного тестирования только открытого интерфейса кода. При правильном выполнении (с использованием TDD) закрытые методы вашего кода будут просто рефакторингом предыдущего общедоступного кода и будут иметь достаточный охват тестами через общедоступные методы. Конечно, это правило, а не закон, поэтому могут возникнуть ситуации, когда вы захотите протестировать частный метод. В этих случаях вы можете создать метод доступа и использовать отражение для вызова частного метода.
Еще одна рекомендация, которую я хотел бы сделать, - использовать модульное тестирование и покрытие кода в тандеме. Покрытие кода может быть полезной эвристикой, чтобы определить, когда вам нужно больше тестов. Отсутствие охвата следует использовать в качестве руководства, чтобы указать, где может потребоваться дополнительное тестирование. Это не означает, что вам нужно 100% покрытие - некоторый код может быть достаточно простым, чтобы не требовать модульного теста (например, автоматических свойств), и они могут не затрагиваться вашими существующими тестами.
У меня была пара проблем со статьей. Вероятно, самым большим является отсутствие абстракции от базы данных для модульных тестов. Вероятно, есть некоторые интеграционные тесты, которые должны идти против db - возможно, при тестировании функциональности триггера или ограничения, если вы не можете убедить себя в их правильности в противном случае. В целом, однако, я считаю, что вы должны реализовать свой доступ к данным в виде интерфейсов, а затем смоделировать фактические реализации в своих модульных тестах, чтобы не было необходимости фактически подключаться к базе данных. Я обнаружил, что мои тесты выполняются быстрее, и поэтому я выполняю их чаще, когда делаю это. Создание «поддельного» интерфейса базы данных может занять некоторое время, но его можно использовать повторно, если вы придерживаетесь того же шаблона проектирования для доступа к данным.
Наконец, я бы порекомендовал использовать nUnit с TestDriven.Net - очень полезный плагин, независимо от того, используете ли вы nUnit или MSTest. Делает его очень удобным для запуска или отладки тестов с помощью контекстного меню, вызываемого правой кнопкой мыши.