Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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!

like image 516
dg90 Avatar asked Feb 22 '12 07:02

dg90


People also ask

What is a unit test in coding?

Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation. This testing methodology is done during the development process by the software developers and sometimes QA staff.

How do you create a unit test?

To get started, select a method, a type, or a namespace in the code editor in the project you want to test, right-click, and then choose Create Unit Tests. The Create Unit Tests dialog opens where you can configure how you want the tests to be created.


2 Answers

From my perspective...

Your logic is not be able to test if you interact with database via DataBaseEntities context(ProductionEntities) directly. because your logic that depend on 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.

like image 118
Pongsathon.keng Avatar answered Oct 19 '22 19:10

Pongsathon.keng


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:

// 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. 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.

like image 2
Lunivore Avatar answered Oct 19 '22 21:10

Lunivore