私は単体テストに飛び込み始めたばかりで、リポジトリパターンとIoCを把握し始めたところです。しかし、その一部が少しばかげているように見えるので、私はそれを完全には理解していないと思います。説明させてください。
私のコントローラー:
public class UserProfileController : ApiController
{
private IUserProfileRepository repository;
// Optional constructor, passes repository, allows dependency injection
public UserProfileController(IUserProfileRepository userProfileRepository)
{
this.repository = userProfileRepository;
}
// GET api/UserProfile
// Returns a list of all users
public IEnumerable<UserProfile> Get()
{
// Only Admins can see a list of users
if (Roles.IsUserInRole("Admin"))
{
return repository.Get();
}
else
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.Forbidden)
{
ReasonPhrase = "Administrator access required"
});
}
}
// Other methods, etc.
(私には依存関係Roles.IsUserInRole( "Admin")があり、抽象化する方法がわからないため、いくつかの問題が発生することに注意してください)。
私の典型的なリポジトリインターフェイス:
public interface IUserProfileRepository : IDisposable
{
IEnumerable<UserProfile> Get();
// Other methods, etc.
}
レポ:
public class UserProfileRepository : IUserProfileRepository, IDisposable
{
private OfootContext context;
public UserProfileRepository(OfootContext context)
{
this.context = context;
}
public IEnumerable<UserProfile> Get()
{
return context.UserProfiles.AsEnumerable();
}
// ... More code
したがって、すべてが正常に見えます。ビジネスロジックからビジネスアクセス層を抽象化し、単体テストを実行するための偽のリポジトリを作成できるようになりました。
偽のレポ:
public class FakeUserProfileRepository : IUserProfileRepository, IDisposable
{
private List<UserProfile> context;
public FakeUserProfileRepository(List<UserProfile> context)
{
this.context = context;
}
public IEnumerable<UserProfile> Get()
{
return context.AsEnumerable();
}
およびテスト:
[TestMethod]
public void GetUsers()
{
// Arrange
var items = new List<UserProfile>()
{
new UserProfile
{
UserId = 1,
Username = "Bob",
},
new UserProfile
{
UserId = 2,
Username = "Bob2",
}
};
FakeUserProfileRepository repo = new FakeUserProfileRepository(
items);
UserProfileController controller = new UserProfileController(
repo);
// Act
IEnumerable<UserProfile> result = controller.Get();
// Assert
Assert.IsNotNull(result);
}
同じページにいるので(そして「コードの臭い」を自由に指摘してください)、ここに私の考えがあります:
- 偽のリポジトリでは、Entity Frameworkロジックをすべて再実装し、Listオブジェクトを処理するように変更する必要があります。これは、デバッグする必要があるチェーン内のより多くの作業とより多くのリンクです。
- 単体テストに合格した場合、EFにアクセスするコードについては何も表示されないため、アプリケーションが失敗する可能性があります。これは、EFコードを個別にテストして、データベースにヒットさせる必要があることを意味します。
- #1から、単体テストがEFコードをテストしていない場合は、コントローラーでの認証、承認、およびユーザー作成コードを処理しているだけです。WebSecurityクラスとRolesクラスが私のデータベースにヒットするため、これは不可能です。
- データベースを使用してEFコード(ポイント#2)をテストし、コントローラーコード(認証と承認、ポイント#3)をテストするデータベースが必要な場合は、リポジトリを使用して抽象化する必要があります。(IContextなどを使用して)コンテキストを抽象化し、DropCreateDatabaseAlwaysクラスを使用して入力されたテストデータベースに接続しないのはなぜですか?
ユーザーアカウントのガベージを抽象化する方法を見つけたとしても、コードをシャッフルして、コンテキストを置き換えることができるコードをさらに作成しています(おそらく、2倍になるかもしれません。偽物を作成する必要があるため)。
私の質問は:私は何が欠けていますか?それは全体的なコンセプトですか、それとも特定のものですか?