Estoy tratando de crear un repositorio falso para pruebas unitarias con un objeto de clase que tiene una relación uno a muchos. Estoy usando ASP.NET MVC y Linq a SQL. Mi referencia es el libro "Pro ASP.NET MVC Framework" de Steven Sanderson.Cómo crear un repositorio falso con una asociación 1-to-many para MVC
He creado las clases de entidad con la asociación:
[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; }
}
Y una interfaz abstracta para el repositorio:
public interface IMusicRepository
{
IQueryable<Album> Albums { get; }
IQueryable<Track> Tracks { get; }
}
yo era capaz de crear un repositorio falso para los álbumes - 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(); }
}
}
Que funciona bien siempre y cuando no intente acceder a ninguna pista. En otras palabras, Album.Title funciona, pero el acceso a Album.Tracks.Count() generará una excepción de Referencia nula. No estaba seguro de si Linq-To-SQL o Linq-To-Objects recogían la asociación y la usaban automáticamente con los objetos falsos o no.
El problema es que no importa lo que intento y parece que no puedo asignar la clase de Pistas a Álbum. Sé que EntitySet está basado en IEnumerable, pero ha sido un desafío lanzar la lista de Enumerable a un EntitySet.
álbum está a la espera de una EntitySet pero la única manera que he sido capaz de pasar de que en es a través de un ayudante de encargo:
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;
}
}
Esto es lo más cerca que he llegado:
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(); }
}
}
sin embargo cuando intento de acceso Album.Tracks me sale
System.NullReferenceException: referencia a objeto no establecida como una instancia de una junta bject.
Aquí está la prueba implamentation/unidad:
[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!");
}
He pasado días en busca de una respuesta a esta pregunta y no he encontrado ningún ejemplo de modo que si alguien sería capaz de publicar un trabajo ejemplo de respuesta Estoy seguro de que otros también estarían interesados.
Soy muy nuevo en MVC y pruebas unitarias, así que por favor vaya fácil conmigo. También tengo IoC y Moq a mano, pero sé mucho menos sobre esto, pero estoy planeando usar ambos con este proyecto. Si hay una mejor manera de hacerlo, ¡soy todo oídos! Gracias.
¿Tiene el código que está utilizando para acceder a las pistas? ES DECIR. su código de implementación? Eso podría ayudar a la depuración. Si está haciendo Album.Tracks.Count(), entonces la razón podría ser que no está asignando las pistas correctamente, sino que depende del código de implementación. – Odd
Buena idea: he publicado mi código de prueba/implementación de la unidad. – ColinICN