2010-03-01 7 views
6

일대 다 관계가있는 클래스 개체를 사용하여 단원 테스트를위한 가짜 리포지토리를 만들려고합니다. ASP.NET MVC 및 Linq SQL 사용하고 있습니다. 내 참조는 Steven Sanderson의 "Pro ASP.NET MVC Framework"입니다.MVC 용 일대 다 연관을 사용하여 가짜 저장소를 만드는 방법

[Table(Name = "Albums")] 
public class Album 
{ 
    [Column(IsDbGenerated = true, IsPrimaryKey = true)] 
    public int AlbumID { get; set; } 
    [Column] 
    public string Title { get; set; } 

    private EntitySet<Track> _tracks; 

    [Association(Storage = "_tracks", ThisKey = "AlbumID", OtherKey = "AlbumID")] 
    public EntitySet<Track> Tracks 
    { 
     get { return _tracks; } 
     set { _tracks.Assign(value); } 
    } 
} 

[Table(Name = "Tracks")] 
public class Track 
{ 
    [Column(IsPrimaryKey = true)] 
    public int TrackID { get; set; } 
    [Column] 
    public string Title { get; set; } 
    [Column] 
    public int AlbumID { get; set; } 
} 

그리고 저장소에 대한 추상적 인 인터페이스 :

나는 협회와 엔터티 클래스를 만든

public interface IMusicRepository 
{ 
    IQueryable<Album> Albums { get; } 
    IQueryable<Track> Tracks { get; } 
} 

내가 앨범 가짜 저장소를 만들 수 있었다 - FakeMusicRepository를 :

public class FakeMusicRepository : IMusicRepository 
{ 

    private static IEnumerable<Track> fakeTracks = new List<Track> 
    { 
     new Track {AlbumID = 1, TrackID = 1, Title = "Flood"}, 
     new Track {AlbumID = 1, TrackID = 2, Title = "Liquid"}, 
     new Track {AlbumID = 2, TrackID = 1, Title = "Song 1"}, 
     new Track {AlbumID = 2, TrackID = 2, Title = "Song 2"} 
    }.AsEnumerable(); 

    private static IQueryable<Album> fakeAlbums = new List<Album> 
    { 
      new Album {AlbumID = 1, Title = "Jars of Clay"}, 
      new Album {AlbumID = 2, Title = "Wind in the Wheat"} 
    }.AsQueryable(); 


    public IQueryable<Album> Albums 
    { 
     get { return fakeAlbums; } 
    } 

    public IQueryable<Track> Tracks 
    { 
     get { return fakeTracks.AsQueryable(); } 
    } 

} 

어떤 트랙에도 액세스하지 않는 한 올바르게 작동합니다. 즉, Album.Title은 작동하지만 Album.Tracks.Count()에 액세스하면 null 참조 예외가 생성됩니다. 나는 Linq-To-SQL 또는 Linq-To-Objects가 연관을 픽업하여 가짜 오브젝트와 자동으로 사용하는지 아닌지 잘 몰랐다.

문제는 내가 뭘 시도하든간에 트랙을 앨범 클래스에 할당 할 수없는 것입니다. EntitySet은 IEnumerable을 기반으로하지만 Enumerable 목록을 EntitySet으로 캐스팅하는 것은 어려웠습니다.

앨범은 EntitySet하지만를 기대하고 내가 그의를 통과 할 수 있었던 유일한 방법은 사용자 지정 도우미를 통해입니다 :

public static class EntityCollectionHelper 
{ 
    public static EntitySet<T> ToEntitySet<T>(this IEnumerable<T> source) where T : class 
    { 
     EntitySet<T> set = new EntitySet<T>(); 
     set.AddRange(source); 
     return set; 
    } 
} 

이 내가 왔어요로 가깝다 :

public class FakeMusicRepository2 : IMusicRepository 
{ 
    private static IEnumerable<Track> fakeTracks = new List<Track> 
    { 
     new Track {AlbumID = 1, TrackID = 1, Title = "Flood"}, 
     new Track {AlbumID = 1, TrackID = 2, Title = "Liquid"}, 
     new Track {AlbumID = 2, TrackID = 1, Title = "Song 1"}, 
     new Track {AlbumID = 2, TrackID = 2, Title = "Song 2"} 
    }.AsEnumerable(); 

    private static EntitySet<Track> Tracks1 = (from t in fakeTracks where t.AlbumID == 1 select t).ToEntitySet(); 
    private static EntitySet<Track> Tracks2 = (from t in fakeTracks where t.AlbumID == 2 select t).ToEntitySet(); 

    private static IQueryable<Album> fakeAlbums = new List<Album> 
    { 
      new Album {AlbumID = 1, Title = "Jars of Clay", Tracks=Tracks1}, 
      new Album {AlbumID = 2, Title = "Wind in the Wheat", Tracks=Tracks2} 
    }.AsQueryable(); 


    public IQueryable<Album> Albums 
    { 
     get { return fakeAlbums; } 
    } 

    public IQueryable<Track> Tracks 
    { 
     get { return fakeTracks.AsQueryable(); } 
    } 

} 
개체 참조 오의 인스턴스로 설정되지 않았습니다 : 나는 액세스 Album.Tracks하려고 할 때

그러나 나는

System.NullReferenceException 얻을 피하십시오.

[Test] 
    public void Test_FakeMusicRepository() 
    { 
     // Arrange: Setup Repository 
     var dc = new FakeMusicRepository2(); 

     // Act: 
     var albums = dc.Albums.AsQueryable(); 
     // Load the first test location 
     Album album = dc.Albums.First(); 

     // Assert: That there are records in the Album Object 
     Assert.Greater(albums.Count(), 0, "No Albums Records Returned!"); 

     //Assert that our first Album is not Null 
     Assert.IsNotNull(album, "returned Album is Null!"); 
     // Assert: That we have the correct Album 
     Assert.AreEqual(album.AlbumID, 1, "Returned Album ID is not correct!"); 

     // Try to Count the related sub table (Tracks) 
     var trackCount = album.Tracks.Count(); 

     // Try to get the first Track 
     var track1 = album.Tracks.FirstOrDefault(); 


     // Assert: The Album has Tracks 
     Assert.Greater(trackCount, 0, "Album has no Tracks"); 

     // Assert: That First track is not Null 
     Assert.IsNotNull(track1, "Track1 object was Null!"); 

     // Assert: That Track1 has data 
     Assert.IsNotNull(track1.TrackID, "Track1's ID was Null!"); 
    } 

나는이 질문에 대한 대답을 찾고 일에 썼다 누군가가 작업을 게시 할 수있을 것입니다 그래서 만약 예제를 발견하지 않았습니다 : 여기

는 implamentation/단위 테스트입니다 answer example 다른 사람들도 관심을 가질 것이라고 확신합니다.

저는 MVC 및 단위 테스트에 새로운 것이므로 나와 함께 가시기 바랍니다. 나는 IoC와 Moq를 가지고 있지만 이것들에 관해서는 더 잘 알지 못한다. 그러나 나는이 프로젝트와 함께 사용할 것을 계획하고있다. 이 작업을 수행하는 더 좋은 방법이 있다면 나는 모두 귀입니다! 감사.

+0

트랙에 액세스하는 데 사용하는 코드가 있습니까? I.E. 당신의 구현 코드? 디버깅에 도움이 될 수 있습니다. Album.Tracks.Count()를 수행하는 경우 트랙을 올바르게 지정하지 않았지만 구현 코드에 따라 달라질 수 있습니다. – Odd

+0

좋은 아이디어 - 단위 테스트/구현 코드를 게시했습니다. – ColinICN

답변

2

Album 클래스는 조금 이상하고, 특히이 부분 보인다

private EntitySet<Track> _tracks; 

[Association(Storage = "_tracks", ThisKey = "AlbumID", OtherKey = "AlbumID")] 
public EntitySet<Track> Tracks 
{ 
    get { return _tracks; } 
    set { _tracks.Assign(value); } 
} 

_tracks private 멤버에 값이 할당 결코이며, 당신은 예외를 throw 세터에서의 Assign 메서드를 호출합니다. 그건 그렇고 컴파일러가 경고 했어야했다.당신은 기본값을 제공하는 시도하거나 Assign 메서드를 호출하기 전에 세터에서 널을 확인 할 수 : 확장 방법은 좋은 것 같은 IEnumerable<T>EntitySet<T>로 변환하는

private EntitySet<Track> _tracks = new EntitySet<Track>(); 

다른 것보다.

그리고 당신은 가짜 앨범을 할당 할 때 마지막으로 당신은 트랙을 설정해야합니다

여기
private static IQueryable<Album> fakeAlbums = new List<Album> 
{ 
     new Album 
     { 
      AlbumID = 1, 
      Title = "Jars of Clay", 
      Tracks = fakeTracks.ToEntitySet() 
     }, 
     new Album 
     { 
      AlbumID = 2, 
      Title = "Wind in the Wheat", 
      Tracks = fakeTracks.ToEntitySet() 
     } 
}.AsQueryable(); 
+0

감사합니다. Darivn - _tracks = new EntitySet 추가 (); 그것을 해결했다. 당신이 말했듯이 _tracks에 값을 할당하지 않았습니다. MSDN 예제와 책은 할당없이 이런 식으로 코드를 보여줍니다. Linq To SQL이 당신을 대신해 처리 할 것입니다. 그렇습니다 compier는 경고를 던지고 있었지만 Linq가 SQL로 작동했기 때문에 모든 것이 정상이라고 생각했습니다. 앨범 개체에 트랙을 지정하는 것을 잊어 버리는 것이 옳습니다. 그것을 보여주는 코드 블록에 붙여 넣기를 놓쳤다. 누락 된 코드 블록을 추가하고 단위 테스트 구현 코드도 포기할 것입니다. 감사! – ColinICN

1

는 수정 (작업) 앨범 클래스입니다 :

[Table(Name = "Albums")] 
public class Album 
{ 
    [Column(IsDbGenerated = true, IsPrimaryKey = true)] 
    public int AlbumID { get; set; } 
    [Column] 
    public string Title { get; set; } 

    private EntitySet<Track> _tracks = new EntitySet<Track>(); 

    [Association(Storage = "_tracks", ThisKey = "AlbumID", OtherKey = "AlbumID")] 
    public EntitySet<Track> Tracks 
    { 
     get { return _tracks; } 
     set { _tracks.Assign(value); } 
    } 
} 

[Table(Name = "Tracks")] 
public class Track 
{ 
    [Column(IsPrimaryKey = true)] 
    public int TrackID { get; set; } 
    [Column] 
    public string Title { get; set; } 
    [Column] 
    public int AlbumID { get; set; } 
} 

problme 내가 '년후이었다 Darin이 지적한 것처럼 Album 객체의 인스턴스를 만들지 않습니다. 단위 테스트가 올바르게 작동합니다. 가짜 저장소와 실제 데이터를 모두 테스트했으며 모든 것이 작동합니다! MSDN 예제 (http://msdn.microsoft.com/en-us/library/bb425822.aspx)가 할당을 표시하지 않았다는 것이 이상합니다.