2012-02-22 73 views
4

我得到了一些我想测试的业务逻辑代码。
目前我只知道如何在没有其他依赖的逻辑代码上编写单元测试。如何为此业务逻辑代码编写可靠的单元测试?

任何人都可以指出我如何测试这个功能的好方向,也许举个例子吗?

是测试这个集成测试的唯一方法,还是我必须使用模拟/存根?

/// <summary> 
/// Gets the scan face file by a MemberID 
/// </summary> 
/// <param name="MemberID">The ID of a member</param> 
/// <returns>A scan face file in byte array format</returns> 
public byte[] GetScanFileFaceByMemberID(int MemberID) 
{ 
    byte[] scanFileFace; 

    using (ProductionEntities entityContext = new ProductionEntities()) 
    { 
     scanFileFace = (from scan in entityContext.tblScan 
        where scan.MEMBERID == MemberID 
        select scan.scanFileFace).Single(); 
    } 

    return scanFileFace; 
} 

变化(I实现存储库&犀牛制品):

BL:

public byte[] GetScanFileFaceByMemberID(int MemberID) 
{ 
    byte[] scanFileFace; 

    var query = Repository.GetAll<tblScan>().Where(bl => bl.MEMBERID == MemberID).Single(); 

    scanFileFace = query.scanFileFace; 

    return scanFileFace; 
} 

单元测试:

[TestMethod] 
public void GetScanFileFace_ExistingScan_ReturnByteArray() 
{ 
    //Make testScan 
    List<tblScan> testScan = PrepareTestDataScan(); 

    //Arrange 
    KlantenBL klantenBL = new KlantenBL(); 

    klantenBL.Repository = MockRepository.GenerateMock<IRepository>(); 
    klantenBL.Repository.Stub(bl => bl.GetAll<tblScan>()).IgnoreArguments().Return(testScan); 

    //Act 
    var result = klantenBL.GetScanFileFaceByMemberID(2); 

    //assert 
    Assert.AreEqual(result.GetType().Name, "Byte[]"); 
    Assert.AreEqual(result.Length, 10); 
} 

//Prepare some testData 
private List<tblScan> PrepareTestDataScan() 
{ 
    List<tblScan> scans = new List<tblScan>(); 

    //Declare some variables 
    byte[] byteFile = new byte[4]; 
    byte[] byteFile10 = new byte[10]; 

    DateTime date = new DateTime(2012,01,01); 

    scans.Add(new tblScan { SCANID = 1, MEMBERID = 1, scanFileFace = byteFile, Hair = byteFile, scanFileAvatar = byteFile, scanFileMeasurements = byteFile, scanDate = date }); 
    scans.Add(new tblScan { SCANID = 2, MEMBERID = 2, scanFileFace = byteFile10, Hair = byteFile, scanFileAvatar = byteFile, scanFileMeasurements = byteFile, scanDate = date }); 
    scans.Add(new tblScan { SCANID = 3, MEMBERID = 3, scanFileFace = byteFile, Hair = byteFile, scanFileAvatar = byteFile, scanFileMeasurements = byteFile, scanDate = date }); 

    return scans; 
} 

库:

public IList<T> GetAll<T>() 
{ 
    DZine_IStyling_ProductionEntities context = GetObjectContext(); 
    IList<T> list = context 
     .CreateQuery<T>(
     "[" + typeof(T).Name + "]") 
     .ToList(); 
    ReleaseObjectContextIfNotReused(); 
    return list; 
} 

public IList<T> GetAll<T>(Func<T, bool> expression) 
{ 
    DZine_IStyling_ProductionEntities context = GetObjectContext(); 
    IList<T> list = context 
     .CreateQuery<T>(
     "[" + typeof(T).Name + "]") 
     .Where(expression) 
     .ToList(); 
    ReleaseObjectContextIfNotReused(); 
    return list; 
} 

这个工作非常感谢大家!

回答

3

从我的角度......

你的逻辑是不能够直接测试,如果你通过DataBaseEntities上下文(ProductionEntities)与数据库进行交互。因为你的逻辑取决于ProductionEntities。

我建议您按照Repository Pattern为您的数据访问层。你将能够让你的代码成为可测性逻辑。该模式将帮助您从逻辑注入数据访问层。

我也想推荐你遵循依赖注入模式。这种模式将帮助您更轻松地对代码进行单元测试。您将能够使用模拟框架(如Rhino模拟)来帮助您进行单元测试。

2

这看起来不像一块业务逻辑和一块数据访问一样多。

可以存根通过一个接口使用依赖注入,是lambda您ProductionEntities以确保您的“使用”以同样的方式工作:

// Use this in real code 
public class MyClass() : MyClass(() => new ProductionEntities()) 
{ 
} 

// Use this in your test 
public class MyClass(Func<IHaveEntities> entities) 
{ 
    _entities = entitites; 
} 

public byte[] GetScanFileFaceByMemberID(int MemberID) 
{ 
    byte[] scanFileFace; 

    using (IHaveEntities entityContext = _entities()) 
    { 
     scanFileFace = (from scan in entityContext.tblScan 
       where scan.MEMBERID == MemberID 
       select scan.scanFileFace).Single(); 
    } 

    return scanFileFace; 
} 

不过,我认为这将是矫枉过正。在某些情况下,您确实需要访问您的数据。 @ pongsathon-keng所说的公平 - 使用存储库模式将会有所帮助 - 但我认为这是属于的代码,在存储库中。这似乎很简单,我不会担心打破对数据的依赖。

您既可以使用集成测试来测试这件作品,也可以测试整个系统,并确保它的这一部分与其他部分搭配良好。

如果您将每个测试看作是如何使用代码的示例,可能会有所帮助。这不是真的在那里测试你的代码,以帮助你探索它应该做什么,不应该做什么,以及其他人如何使用它。如果它在集成时使用代码才有意义,请编写集成测试。否则,你可以使用上面的模式注入一个模拟。