简体   繁体   English

如何为此业务逻辑代码编写可靠的单元测试?

[英]How to write a solid unit test for this business logic code?

I got some business logic code I want to test. 我得到了一些要测试的业务逻辑代码。
At the moment I only know how to write unit test on logic code that hasn't other dependencies. 目前,我只知道如何在没有其他依赖项的逻辑代码上编写单元测试。

Can anyone point me in the good direction of how to test for example this function and maybe give an example? 谁能为我指出如何测试此功能的良好方向,并举个例子?

Is the only way to test this an integration test or do I have to use mock/stub? 是测试此集成测试的唯一方法,还是必须使用模拟/存根?

/// <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;
}

CHANGES (I implemented Repository & rhino mocks): 更改(我实现了存储库和犀牛模拟):

BL: BL:

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

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

    scanFileFace = query.scanFileFace;

    return scanFileFace;
}

Unit test: 单元测试:

[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;
}

Repository: 仓库:

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;
}

This worked perfectly thanks all! 一切正常,谢谢!

From my perspective... 依我看来...

Your logic is not be able to test if you interact with database via DataBaseEntities context(ProductionEntities) directly. 您的逻辑无法测试您是否直接通过DataBaseEntities context(ProductionEntities)与数据库进行交互。 because your logic that depend on ProductionEntities. 因为您的逻辑取决于ProductionEntities。

I would recommend you to follow Repository Pattern for your data access layer. 我建议您遵循存储库模式进行数据访问层。 You would be able to make you code to be testability logic. 您将能够使您的代码成为可测试性逻辑。 The pattern will help you to inject data access layer from logic. 该模式将帮助您从逻辑注入数据访问层。

I also would like to recommend you to follow dependency injection pattern. 我还建议您遵循依赖项注入模式。 This pattern will help you to do unit test your code easier. 此模式将帮助您更轻松地对代码进行单元测试。 You will be able to use mock framework like Rhino mock to help you on unit testing. 您将能够使用Rhino模拟之类的模拟框架来帮助您进行单元测试。

This doesn't look like a piece of business logic as much as a piece of data access. 这看起来不像业务逻辑,而是数据访问。

You could stub out your ProductionEntities using dependency injection via an interface, with a lambda to ensure that your "using" works in the same way: 可以通过接口使用依赖项注入来生产ProductionEntities,并使用lambda来确保您的“ using”以相同的方式工作:

// 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;
}

However, I think this will be overkill. 但是,我认为这太过分了。 At some point, you do need to access your data. 在某些时候,您确实需要访问数据。 What @pongsathon-keng has said is fair - using a repository pattern will help - but I think this is code that belongs in the repository. 什么@ pongsathon铿说是公平的-使用存储库模式将帮助-但我认为这是仓库属于代码。 It seems simple enough that I wouldn't worry about breaking up the dependency on the data. 看起来很简单,我不必担心打破对数据的依赖。

You can either use an integration test just to test this piece, or you could just test the whole system and make sure that this part of it plays nicely with the other parts. 您可以只使用集成测试来测试此部分,也可以只测试整个系统,并确保该部分与其他部分配合良好。

It may help if you think of each test just as an example of how to you use your code. 如果您将每个测试都看作是如何使用代码的示例,则可能会有所帮助。 It's not really there to test your code as much as to help you explore what it should and shouldn't do, and how other people can use it. 测试代码并不能真正帮助您探究它应该做和不应该做的事情以及其他人如何使用它。 If it only makes sense to use the code when it's integrated, write an integration test. 如果仅在集成时使用代码有意义,请编写集成测试。 Otherwise, you can use the pattern above to inject a mock. 否则,您可以使用上述模式来注入模拟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM