问题描述:

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!

网友答案:

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.

网友答案:

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.

相关阅读:
Top