Thursday, November 3, 2011

Mocked Repository and Generic Constraints

So, a productive couple of days - three issues resolved.

Reinstated a Repository - Moq cannot mock EF IDbSet so I decided that bringing the repository back would be a good idea. Example unit test below:

[TestMethod]
public void ListInventoryTest()
{
Mock<IDbContext> context = new Mock<IDbContext>();
Mock<AssetRepository> assetRepository = new Mock<AssetRepository>(context.Object);
Mock<StockpileRepository> stockpileRepository = new Mock<StockpileRepository>(context.Object);
List<Asset> assets = new List<Asset>();
assets.Add(new Asset() { AssetId = 1 });
assets.Add(new Asset() { AssetId = 2 });

Stockpile stockpile = new Stockpile() { StockPileId = 1, Assets = assets };

//assetRepository.Setup(x=>x.GetSingle(It.IsAny<expression<func<asset, bool="">>>())).Returns(asset);<expression<func<asset,>
stockpileRepository.Setup(x => x.GetSingle(It.IsAny<Expression<Func<Stockpile, bool>>>(), It.IsAny<IEnumerable<string>>(), It.IsAny<bool>())).Returns(stockpile);
var inventoryService = new InventoryService( stockpileRepository.Object, assetRepository.Object );
List<Asset> rv = inventoryService.ListInventory("Hailes", "Jita01");
Assert.IsNotNull(rv);
Assert.IsTrue(rv.Count == 2);
}
Then, now that I had a repository I could add a Null Object pattern solution to my repository, which was a bit tricker than I expected. In order to create a new T in the generic method, I needed to include a generic constraint to ensure T had a blank constructor.

public virtual T GetSingle<T>(Expression<Func<T, bool>><func whereClause, IEnumerable<string> customIncludes = null, bool overrideDefaultIncludes = false) where T : new()<string><func
{
IQueryable query = (IQueryable)this.ApplyIncludesToSet(customIncludes, overrideDefaultIncludes);
T val = query.SingleOrDefault(whereClause);
if (val == null)
{
val = new T();
}
return val;
}
The final issue I resolved was picking an appropriate lifetime manager for the EF DbContext when running in an 'application' context. Using the PerResolveLifetimeManager ensures that when resolving a class, any common Dependency in the entire resolve pat are shared - this means that a service with two repository dependencies, which both depend on a dbContext, will both use the same dbContext when the service is resolved - yay. This does exactly what I want it to, each operation should use a new service instance, which will use a single dbContext across all repository actions within that method.

So yeah, productive (and thanks to @wolfbyte for the generic constraint tip).

Next job to flesh out my unit tests, and continue on the functionality, as this covered the majority of my architecture issues.

No comments:

Post a Comment