Я пытаюсь создать поддельный репозиторий для модульного тестирования с объектом класса, который имеет отношение один ко многим. Я использую ASP.NET MVC и Linq to SQL. Моя ссылка - книга Стивена Сандерсона "Pro ASP.NET MVC Framework".
Я создал классы сущностей с ассоциацией:
[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 () будет сгенерировано пустое исключение Reference. Я не был уверен, что Linq-To-SQL или Linq-To-Objects уловят ассоциацию и будут использовать ее автоматически с поддельными объектами или нет.
Проблема в том, что независимо от того, что я пытаюсь и не могу назначить треки для класса Album. Я знаю, что 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!");
}
Я потратил несколько дней на поиск ответа на этот вопрос и не нашел ни одного примера, поэтому, если кто-то сможет опубликовать пример рабочего ответа, я уверен, что другие тоже будут заинтересованы.
Я очень новичок в MVC и модульном тестировании, поэтому, пожалуйста, будьте спокойны со мной. У меня также есть IoC и Moq, но я знаю об этом еще меньше, но я планирую использовать оба в этом проекте. Если есть лучший способ сделать это, то я весь слух! Спасибо.