±à¼ÍƼö: |
±¾ÎÄÀ´×Ôcnblogs,±¾ÎıàдµÄµ¥Ôª²âÊÔ¶¼ÊÇ»ùÓÚÒÑÓдúÂë½øÐвâÊÔ£¬¶ø²»ÊÇTDD³«µ¼µÄÏÖÓвâÊÔºóÓпÉÒÔ¹¤×÷µÄ´úÂ룬²»Í¬Ë¼ÏëÖ¸µ¼ÏÂд³öµÄ²âÊÔ´úÂë¿ÉÄܲ»Ì«Ò»Ñù¡£ |
|
×î½üµÄÏîÄ¿ÖÐдÁËÒ»¸ö¾Þ³¤µÄº¯Êý£¬µ÷ÊÔµÄʱºò×ÜÊÇ·¢ÏÖ¸÷ÖÖDZÔÚµÄÎÊÌ⣬һ±éÒ»±éµÄF5Æô¶¯µ÷ÊÔ£¬¼üÅ̶¼¿ì°´ÀÃÁË£¬ÄǸöº¯Êý»¹Ã»ÅÜͨ¡£ÏëÁËÏ룬Ū¸öµ¥Ôª²âÊÔºÜÓбØÒª£¬Ëµ¸É¾Í¸É¡£ÕÒÀ´xUnitµÈ°Ñµ¥Ôª²âÊÔ¸ãÁËÆðÀ´¡£ËµÀ´Õ⻹ÊǵÚÒ»´ÎÕý°Ë¾µÄ¸ãµ¥Ôª²âÊÔ£¬ÏëÏëÓбØÒª°ÑÕâ¸ö¹ý³Ì¼Ç¼һÏ£¬ÓÚÊÇÕâÆªÎÄÕ¾͵®ÉúÁË¡£
½øÐе¥Ôª²âÊÔ´úÂë±àдµÄ¹ý³ÌÖÐÊÕ»ñ»¹Õæ²»ÉÙ£¬±ÈÈç°ÑÄǸö¾Þ³¤µÄº¯ÊýÖØ¹¹Îª4¸ö¹¦ÄÜÏà¶Ô¶ÀÁ¢£¬´óСÊÊÖеĺ¯Êý¡£ÁíÍâд²âÊÔ¿ÉÒÔÒÔÓû§µÄ½Ç¶ÈʹÓú¯Êý£¬´Ó¶ø·¢ÏÖÁ˼¸¸ö֮ǰûÓÐÏëµ½µÄÓ¦¸Ã½øÐÐÂß¼Åжϵĵط½²¢ÔÚ³ÌÐò´úÂëÖмÓÈëÁËif¶Î¡£ÆäʵÕâЩ¶¼Êǵ¥Ôª²âÊԵĺô¦£¬µ±È»µ¥Ôª²âÊÔµÄÀû¿ÉÄܲ»Ö»ÕâЩ£¬×ÜÖ®Ô½ÔçÔÚÏîÄ¿ÖмÓÈëµ¥Ôª²âÊÔÔ½ÊÇʰ빦±¶¡£
ÕâÆªÎÄÕ¶Ե¥Ôª²âÊÔ×öÁËһЩ×ܽᣬµ±È»×îÖØÒªµÄÊǼǼÁËMocks¹¤¾ßµÄʹÓá£ÔÚÕâ´Îµ¥Ôª²âÊÔ֮ǰÎÒ¶Ôµ¥Ôª²âÊÔµÄÁ˽âÍ£ÁôÔÚ¼¸¸ö²âÊÔ¿ò¼ÜµÄ²âÊÔ·½·¨ÉÏ¡£ÄòâÊÔÔËÐÐÆ÷¸ÉµÄ×î¶àµÄʲ»ÊÇ¡°²âÊÔ¡±¶øÊÇ¡°µ÷ÊÔ¡±¡£¼´Ò»°ã¶¼ÊÇÔÚÒ»¸öÀ༰º¯Êý²»·½±ãÆô¶¯³ÌÐòÀ´µ÷ÊÔʱ£¬¸ãÒ»¸ö²âÊÔÀ࣬ÓòâÊÔÔËÐÐÆ÷µÄµ÷ÊÔ¹¦ÄÜרÃÅÈ¥DebugÕâ¸ö·½·¨¡£ÕâÆäʵҲֻÊÇÓÃÁ˲âÊÔ¿ò¼Ü£¨ºÍ²âÊÔÔËÐÐÆ÷£©ºÜСµÄÒ»²¿·Ö¹¦ÄÜ¡£
ÔÚ¿ªÊ¼ÕýÌâ֮ǰ˵һ˵µ¥Ôª²âÊÔ¹¤¾ßµÄÑ¡Ôñ¡£ÏÖÔÚxUnit.net¼¸ºõ³ÉΪÁË×¼¹Ù·½µÄÑ¡Ôñ¡£xUnit.netÅäÌ×¹¤¾ßÍêÉÆ£¬ÉÏÊÖ¼òµ¥³õ´Î½Ó´¥µ¥Ôª²âÊÔÊǺܺõÄÑ¡Ôñ¡£²âÊÔÔËÐÐÆ÷Ñ¡ÔñÁËResharperµÄxUnit
runner²å¼þ£¨ResharperÒ²ÊÇvs±Ø²»¿ÉÉٵIJå¼þ£©£¬¸öÈËʼÖոоõVS×Ô´øµÄ²âÊÔÔËÐй¤¾ßÔ¶²»ÈçResharperµÄºÃÓá£Mock¿ò¼ÜÑ¡ÔñÁË´óÃû¶¦¶¦µÄRhinoMocks£¬ÉñÒ»ÑùµÄ¿ªÔ´Mock¿ò¼Ü¡£
ÓÉÓÚÎÒÊǵ¥Ôª²âÊÔÐÂÊÖ£¬ÕâÒ²ÊǵÚÒ»´Î±È½Ï×ÐϸµÄдµ¥Ôª²âÊÔ£¬×î´óµÄÌå»á¾ÍÊÇMock¹¤¾ßÒª±ÈTest FrameworkÓë±àдµ¥Ôª²âÊÔ´úÂëµÄÓû§¹ØÏµ¸üÃÜÇС£±¾ÎĽ«´Ó×î¼òµ¥µÄ²âÊÔ¿ªÊ¼ÕùÈ¡½«ËùÓпÉÄÜÓöµ½µÄ²âÊÔÇé¿ö¶¼Ð´³öÀ´£¬ÈçÓв»ÍêÕûÒ²Çë°ïæָ³ö£¬ÈçÓдíÎóÇë²»Áߴͽ̡£
²å²¥Ò»Ï£¬xUnit.netµÄ°²×°ºÜ¼òµ¥£¬´ò¿ªNuget°ü¹ÜÀíÆ÷ÕÒµ½xUnit.net²¢°²×°¾Í¿ÉÒÔÁË£¨Ð´ÕâÆªÎÄÕÂÊÇ×îÐÂÕýʽ°æÊÇ2.0£¬2.1µ½ÁËRC£©£¬¾ÍÊÇһЩ³ÌÐò¼¯¡£RhinoMocksÒ²ÊÇͬÀí¡£ResharperµÄxUnit
Test Runnerͨ¹ýResharperµÄExtension Manager£¨ÓÐÕâôһ¸ö²Ëµ¥ÏÀ´°²×°£¬µã»÷²Ëµ¥µ¯³öÈçÏÂͼµÄ¶Ô»°¿ò£º

ͼ1
дÕâ¶ÎÄÚÈÝʱ£¬xUnit.net Test RunnerÅÅÔÚÏÔÑ۵ĵÚһ룬µã»÷ToggleButtonÇл»µ½Install£¬µã»÷°²×°¾Í¿ÉÒÔÁË£¬ÍêÁËÐèÒªÖØÆôvs¡£
ps.аæµÄResharper Extension Manager»ùÓÚNugetʵÏÖ£¬ÎÒÕâÀïµÄÁªÍ¨¿í´øÁ¬nuget³£ÖÜÆÚÐÔ³é·ç£¬ÓÐʱ²»µÃ²»×ß´úÀí£¬ËٶȹêÂý¡£
1.×î¼òµ¥µÄµ¥Ôª²âÊÔ
ÕâÀïÏÈչʾһ¸ö×î¼òµ¥µÄ·½·¨¼°²âÊÔ£¬Ä¿µÄÊÇÈÃûÓнӴ¥¹ýµ¥Ôª²âÊÔµÄͬѧÓиöÖ±¹ÛÓ¡Ïó£º
±»²â·½·¨ÊÇÒ»¸ö¼ÆËãì³²¨ÄÇÆõÊýµÄ´¿¼ÆËã·½·¨£º
public int Fibonacci(int
n)
{
if (n == 1 || n == 2)
{
return 1;
}
int first = 1;
int second = 1;
for (int i = 2; i < n; i++)
{
var temp = second;
second += first;
first = temp;
}
return second;
} |
²âÊÔ·½·¨£º
[Fact]
public void Test_Fibonacci_N()
{
var act = Fibonacci(10);
var expect = 55;
Assert.True(act == expect);
} |
xUnit×î¼òµ¥µÄʹÓþÍÊÇÔÚ²âÊÔ·½·¨Éϱê¼Ç[Fact]£¬Èç¹ûʹÓÃResharper Test RunnerµÄ»°ÔÚvsµÄ´úÂë´°¿ÚÖпÉÒÔ¿´µ½ÕâÑùÕâÑùÒ»¸öСԲȦ£¬µã»÷¾Í¿ÉÒÔ“ÔËÐД»ò“µ÷ʽ”Õâ¸ö²âÊÔ·½·¨¡££¨ÆäËürunnerÒ²ÀàËÆ£©

ͼ2
ÔÚ²âÊÔ·½·¨ËùÔÚµÄÀàÉùÃ÷ÄÇÐÐÇ°ÃæÒ²ÓÐÒ»¸öÕâ¸öµÄÔ²µã£¬µã»÷ºó¿ÉÒÔÖ´ÐÐÀàÖÐËùÓвâÊÔ·½·¨¡£Èç¹û²âÊÔͨ¹ýÔ²µãÊÇÂÌɫСÇò±êʶ£¬Èç¹û²»Í¨¹ý»áÒÔºìÉ«±ê¼ÇÏÔʾ¡£
ÁíÍâÒ²¿ÉÒÔ´ò¿ªResharperµÄUnitTest´°¿Ú£¬ÀïÃæ»áÁгöÏîÄ¿ÖÐËùÓеĵ¥Ôª²âÊÔ£¬Ò²¿ÉÒÔͨ¹ýÕâ¸öÖ´Ðе¥¸ö»òÅúÁ¿²âÊÔ£º

ͼ3
ÎÒÃÇÖ´ÐÐÉÏÃæµÄ²âÊÔ£¬¿ÉÒÔ¿´µ½ÏÂÃæµÄ½á¹û£º

ͼ4
àÅ £¬ÎÒÃǵIJâÊÔͨ¹ýÁË¡£ÓÐʱºòÎÒÃÇ»¹»á±àдһЩ²âÊÔ£¬²âÊÔÏà·´µÄÇé¿ö£¬»ò±ß½çÇé¿ö¡£È磺
[Fact]
public void Test_Fibonacci_N_Wrong()
{
var act = Fibonacci(11);
var expect = 55;
Assert.False(act == expect);
} |
ÔÚÍŶÓÈËÔ±ÅäÖÃ±È½ÏÆëÈ«µÄÇé¿öÏ£¬Éè¼Æ²âÊÔÓÃÀýÓ¦¸ÃÊDzâÊÔÈËÔ±µÄ¹¤×÷£¬³ÌÐòÔ±°´ÕÕÉè¼ÆºÃµÄ²âÊÔÓÃÀý±àд²âÊÔ·½·¨£¬¶Ô±»²âÊÔ·½·¨½øÐÐÈ«·½ÃæµÄ²âÊÔ¡£
³ýÁËÉÏÃæÓõ½µÄAssert.True/False£¬xUnit»¹ÌṩÁËÈçϼ¸ÖÖ¶ÏÑÔ·½·¨£¨ÒÔ2.0°æÎª×¼£¬±í¸ñ¾¡Á¿¸øÕâЩ·½·¨·ÖÀàÅŵÄÐò£¬¿ÉÄܲ»Ì«ÍêÕû£©£º
¶ÏÑÔ |
˵Ã÷ |
Assert.Equal()
|
ÑéÖ¤Á½¸ö²ÎÊýÊÇ·ñÏàµÈ£¬Ö§³Ö×Ö·û´®µÈ³£¼ûÀàÐÍ¡£Í¬Ê±ÓзºÐÍ·½·¨¿ÉÓ㬵±±È½Ï·ºÐÍÀàÐͶÔÏóʱʹÓÃĬÈϵÄIEqualityComparer<T>ʵÏÖ£¬Ò²ÓÐÖØÔØÖ§³Ö´«ÈëIEqualityComparer<T>
|
Assert.NotEqual()
|
ÓëÉÏÃæµÄÏà·´ |
Assert.Same()
|
ÑéÖ¤Á½¸ö¶ÔÏóÊÇ·ñͬһʵÀý£¬¼´ÅжÏÒýÓÃÀàÐͶÔÏóÊÇ·ñͬһÒýÓÃ
|
Assert.NotSame()
|
ÑéÖ¤×Ö·û´®ÒÔÖ¸¶¨×Ö·û´®½áβ
|
Assert.Empty()
|
ÑéÖ¤¼¯ºÏΪ¿Õ |
Assert.NotEmpty()
|
ÓëÉÏÃæµÄÏà·´ |
Assert.Single()
|
ÑéÖ¤¼¯ºÏÖ»ÓÐÒ»¸öÔªËØ |
Assert.InRange()
|
ÑéÖ¤ÖµÔÚÒ»¸ö·¶Î§Ö®ÄÚ£¬·ºÐÍ·½·¨£¬·ºÐÍÀàÐÍÐèҪʵÏÖIComparable<T>£¬»ò´«ÈëIComparer<T> |
Assert.NotInRange()
|
ÓëÉÏÃæµÄÏà·´ |
Assert.Null()
|
ÑéÖ¤¶ÔÏóΪ¿Õ |
Assert.NotNull()
|
ÓëÉÏÃæµÄÏà·´ |
Assert.StrictEqual()
|
ÅжÏÁ½¸ö¶ÔÏóÑϸñÏàµÈ£¬Ê¹ÓÃĬÈϵÄIEqualityComparer<T>¶ÔÏó
|
Assert.NotStrictEqual()
|
ÓëÉÏÃæÏà·´ |
Assert.IsType()
/Assert.IsType<T>() |
ÑéÖ¤¶ÔÏóÊÇij¸öÀàÐÍ£¨²»ÄÜÊǼ̳йØÏµ£©
|
Assert.IsNotType()/
Assert.IsNotType<T>()
|
ÓëÉÏÃæµÄÏà·´ |
Assert.IsAssignableFrom()/
Assert.IsAssignableFrom<T>()
|
Ñé֤ij¸ö¶ÔÏóÊÇÖ¸¶¨ÀàÐÍ»òÖ¸¶¨ÀàÐ͵Ä×ÓÀà
|
Assert.Subset()
|
ÑéÖ¤Ò»¸ö¼¯ºÏÊÇÁíÒ»¸ö¼¯ºÏµÄ×Ó¼¯
|
Assert.ProperSubset()
|
ÑéÖ¤Ò»¸ö¼¯ºÏÊÇÁíÒ»¸ö¼¯ºÏµÄÕæ×Ó¼¯
|
Assert.ProperSuperset()
|
ÑéÖ¤Ò»¸ö¼¯ºÏÊÇÁíÒ»¸ö¼¯ºÏµÄÕæ³¬¼¯
|
Assert.Collection()
|
ÑéÖ¤µÚÒ»¸ö²ÎÊý¼¯ºÏÖÐËùÓÐÏî¶¼¿ÉÒÔÔÚµÚ¶þ¸ö²ÎÊý´«ÈëµÄAction<T>ÐòÁÐÖÐÏàӦλÖõÄAction<T>ÉÏÖ´Ðжø²»Å׳öÒì³£¡£
|
Assert.All()
|
ÑéÖ¤µÚÒ»¸ö²ÎÊý¼¯ºÏÖеÄËùÓÐÏî¶¼¿ÉÒÔ´«ÈëµÚ¶þ¸öAction<T>ÀàÐ͵IJÎÊý¶ø²»Å׳öÒì³£
¡£ÓëCollection()ÀàËÆ£¬Çø±ðÔÚÓÚÕâÀïAction<T>Ö»ÓÐÒ»¸ö¶ø²»ÊÇÐòÁС£
|
Assert.PropertyChanged()
|
ÑéÖ¤Ö´ÐеÚÈý¸ö²ÎÊýAction<T>ʹ±»²âÊÔINotifyPropertyChanged¶ÔÏó´¥·¢ÁËPropertyChangedʱ¼ä£¬ÇÒÊôÐÔÃûΪµÚ¶þ¸ö²ÎÊý´«ÈëµÄÃû³Æ¡£
|
Assert.Throws()
/Assert.Throws<T>()
Assert.ThrowsAsync()/
Assert.ThrowsAsync<T>() |
ÑéÖ¤²âÊÔ´úÂëÅ׳öÖ¸¶¨Òì³££¨²»ÄÜÊÇÖ¸¶¨Òì³£µÄ×ÓÀࣩ
Èç¹û²âÊÔ´úÂë·µ»ØTask£¬Ó¦¸ÃʹÓÃÒì²½·½·¨ |
Assert.ThrowsAny<T>()
Assert.ThrowsAnyAsync<T>() |
ÑéÖ¤²âÊÔ´úÂëÅ׳öÖ¸¶¨Òì³£»òÖ¸¶¨Òì³£µÄ×ÓÀà
Èç¹û²âÊÔ´úÂë·µ»ØTask£¬Ó¦¸ÃʹÓÃÒì²½·½·¨
|
±àдµ¥Ôª²âÊԵIJâÊÔ·½·¨¾ÍÊÇ´«ËµÖеÄ3¸öA£¬Arrange¡¢ActºÍAssert¡£
ArrangeÓÃÓÚ³õʼ»¯Ò»Ð©±»²âÊÔ·½·¨ÐèÒªµÄ²ÎÊý»òÒÀÀµµÄ¶ÔÏó¡£
Act·½·¨ÓÃÓÚµ÷Óñ»²â·½·¨»ñÈ¡·µ»ØÖµ¡£
AssertÓÃÓÚÑéÖ¤²âÊÔ·½·¨ÊÇ·ñ°´ÆÚÍûÖ´ÐлòÕß½á¹ûÊÇ·ñ·ûºÏÆÚÍûÖµ
´ó²¿·ÖµÄ²âÊÔ´úÂë¶¼Ó¦°´ÕÕÕâ3¸ö²¿·ÖÀ´±àд£¬ÉÏÃæµÄ²âÊÔ·½·¨ÖÐÖ»ÓÐActºÍAssert2²¿·Ö£¬¶ÔÓÚÂß¼Äھ۶Ⱥܸߵĺ¯Êý£¬Õâ2²¿·Ö¾Í¿ÉÒԺܺõŤ×÷¡£ÏñÊÇһЩ¶ÀÁ¢µÄËã·¨µÈ°´ÉÏÃæ±àд²âÊԾͿÉÒÔÁË¡£µ«ÊÇÈç¹û±»²âÊÔµÄÀà»ò·½·¨ÒÀÀµÆäËü¶ÔÏóÎÒÃǾÍÐèÒª±àдArrange²¿·ÖÀ´½øÐгõʼ»¯¡£ÏÂÒ»½Ú¾Í½éÉÜÏà¹ØÄÚÈÝ¡£
2.±»²âÊÔÀàÐèÒª³õʼ»¯µÄÇé¿ö
Ôڴ󲿷ֺÍÊý¾Ý¿â´ò½»µÀµÄÏîÄ¿ÖУ¬ÓÈÆäÊÇʹÓÃEntityFrameworkµÈORMµÄÏîÄ¿ÖУ¬³£³£»áÓÐIRepositoryºÍRepository<T>ÕâÑùµÄÉíÓ°¡£ÎÒËù±È½ÏÔÞͬµÄÒ»ÖÖ¶ÔÕâÖÖ²Ö´¢Àà²âÊԵķ½·¨ÊÇ£ºÊ¹ÓÃÕæÊµµÄÊý¾Ý¿â£¨Õâ¸öÕæÊµÖ¸µÄ·ÇMock£¬Ò»°ãÀ´ËµÊ¹Óò»Í¬ÓÚ¿ª·¢Êý¾Ý¿âµÄ²âÊÔÊý¾Ý¿â¼´¿É£¬Í¨¹ý¸ø²âÊÔ·½·¨´«Èë²âÊÔÊý¾Ý¿âµÄÁ´½Ó×Ö·û´®ÊµÏÖ£©£¬²¢ÇÒÏà¹ØµÄDbContextµÈ¶¼Ö±½ÓʹÓÃEntityFrameworkµÄÕæÊµÊµÏÖ¶ø²»ÊÇMock¡£ÕâÑù£¬ÔÚIRepositoryÖ®ÉϵÄËùÓдúÂëÎÒÃǶ¼¿ÉÒÔIRepositoryµÄMockÀ´×÷ΪʵÏÖ¶ø²»ÓÃÈ¥·ÃÎÊÊý¾Ý¿â¡£
Èç¹û¶ÔÓÚʵÌå´æ´¢µ½Êý¾Ý¿â¿ÉÄÜ´æÔÚµÄÎÊÌâ¸Ðµ½µ£ÐÄ£¬ÈçÀàÐÍÊÇ·ñÆ¥Å䣬ÊôÐÔÊÇ·ñÓпɿյȵȣ¬ÎÒÃÇÒ²¿ÉÒÔרßøÊµÌåдһЩ³Ö¾Ã»¯²âÊÔ¡£ÎªÁËʹÕâ¸ö²âÊԵĴúÂë±àдÆðÀ´¸ü¼òµ¥£¬ÎÒÃÇ¿ÉÒÔ°ÑÉÏÃæ²âÊԺõÄIRepository·â×°³ÉÒ»¸öµ¥¶ÀµÄ·½·¨¹©ÊµÌåµÄ³Ö¾Ã»¯²âÊÔʹÓá£
ÏÂÃæ½«¸ø³öһЩʾÀý´úÂ룺
Ê×ÏÈÊDZ»²âÊÔµÄIRepository
public interface
IRepository<T> where T : BaseEntity
{
T GetById(object id);
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
IQueryable<T> Table { get; }
IQueryable<T> TableNoTracking { get; }
void Attach(T entity);
} |
ÕâÊÇÒ»¸öÏîÄ¿ÖÐ×î³£¼ûµÄIRepository½Ó¿Ú£¬Ò²ÊÇ×î¼òµ¥»¯µÄ£¬Ã»ÓÐÒì²½Ö§³Ö£¬Ã»ÓÐUnit
of WorkÖ§³Ö£¬µ«ÓÃÀ´ÑÝʾµ¥Ôª²âÊÔ×ã¹»ÁË¡£Õâ¸ö½Ó¿ÚµÄʵÏÖ´úÂëEFRepository¾Í²»ÁгöÀ´µÄ£¨ÓÃEntityFrameworkʵÏÖÕâ¸ö½Ó¿ÚµÄ´úÂë´óͬСÒ죩¡£ÏÂÃæ¸ø³öÕë¶ÔÕâ¸ö½Ó¿Ú½øÐеIJâÊÔ²¢·ÖÎö²âÊÔÖеÄһЩϸ½Ú¡£
public class
EFRepositoryTests: IDisposable
{
private const string TestDatabaseConnectionName
= " DefaultConnectionTest";
private readonly IDbContext _context;
private readonly IRepository< User> _repository;/ /ÓþßÌåµÄ·ºÐÍÀàÐͽøÐвâÊÔ£¬Õâ¸ö²»Ó°Ïì¶ÔEFRepository²âÊÔµÄЧ¹û
public EFRepositoryTests()
{
_context = new MyObjectContext (TestDatabaseConnectionName);
_repository = new EfRepository<User>(_context);
}
[Fact]
public void Test_insert_getbyid_table_tablenotracking _delete_success()
{
var user = new User()
{
UserName = "zhangsan",
CreatedOn = DateTime.Now,
LastActivityDate = DateTime.Now
};
_repository.Insert(user);
var newUserId = user.Id;
Assert.True(newUserId > 0);
//ÉùÃ÷еÄContext£¬²»È»²éѯֱ½ÓÓÉDbContext·µ»Ø¶ø²»¾¹ýÊý¾Ý¿â
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository<User> (newContext);
var userInDb = repository.GetById(newUserId);
user.UserName.ShouldEqual(userInDb.UserName);
}
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository< User>(newContext);
var userInDb = repository.Table.Single(r =>
r.Id == newUserId);
user.UserName.ShouldEqual (userInDb.UserName);
}
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository<User> (newContext);
var userInDb = repository.TableNoTracking.Single(r
=> r.Id == newUserId);
user.UserName.ShouldEqual (userInDb.UserName);
}
_context.Entry(user).State.ShouldEqual (EntityState.Unchanged);
_repository.Delete(user);
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository< User>(newContext);
var userInDb = repository.GetById(newUserId);
userInDb.ShouldBeNull();
}
}
[Fact]
public void Test_insert_update_attach_success()
{
var user = new User()
{
UserName = "zhangsan",
CreatedOn = DateTime.Now,
LastActivityDate = DateTime.Now
};
_repository.Insert(user);
var newUserId = user.Id;
Assert.True(newUserId > 0);
//update
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository< User>(newContext);
var userInDb = repository.GetById(newUserId);
userInDb.UserName = "lisi";
repository.Update(userInDb);
}
//assert
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository<User>( newContext);
var userInDb = repository.GetById(newUserId);
userInDb.UserName.ShouldEqual ("lisi");
}
//update by attach& modifystate
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository<User>(newContext);
var userForUpdate = new User()
{
Id = newUserId,
UserName = "wangwu",
CreatedOn = DateTime.Now,
nbsp; LastActivityDate = DateTime.Now
};
repository.Attach(userForUpdate);
var entry = newContext.Entry(userForUpdate);
entry.State.ShouldEqual (EntityState.Unchanged);//assert
entry.State = EntityState.Modified;
repository.Update(userForUpdate);
}
//assert
using (var newContext = new MyObjectContext (TestDatabaseConnectionName))
{
var repository = new EfRepository<User> (newContext);
var userInDb = repository.GetById(newUserId);
userInDb.UserName.ShouldEqual ("wangwu");
}
_repository.Delete(user);
}
public void Dispose()
{
_context.Dispose();
}
} |
Èç´úÂëËùʾ£¬Í¨¹ý2¸ö²âÊÔ·½·¨¸²¸ÇÁ˶ÔIRepository·½·¨µÄ²âÊÔ¡£ÔÚ²âÊÔÀàµÄ³ÉÔ±ÖÐÉùÃ÷Á˱»²âÊԽӿڵĶÔÏóÒÔ¼°ÕâЩ½Ó¿ÚËùÒÀÀµµÄ³ÉÔ±µÄ¶ÔÏó¡£Õâ¸ö³¡¾°ÊDzâÊÔÊý¾Ý²Ö´¢ËùÒÔÕâЩÒÀÀµ¶ÔÏóʹÓÃÕæÊµÀàÐͶø·ÇMock£¨ºóÎÄ»á¼ûµ½Ê¹ÓÃMockµÄÀý×Ó£©¡£È»ºóÔÚ¹¹Ô캯ÊýÖжÔÕâЩ³ÉÔ±½øÐгõʼ»¯¡£ÕâЩ²¿·Ö¶¼ÊDzâÊÔµÄArrange²¿·Ö¡£¼´¶ÔÓÚËùÓвâÊÔ·½·¨Í¨Óõijõʼ»¯ÐÅÏ¢ÎÒÃÇ·ÅÔÚ²âÊÔÀ๹Ô캯ÊýÍê³É£¬Òò²âÊÔ·½·¨¶øÒìµÄArrangeÔÚÿ¸ö²âÊÔ·½·¨ÖÐÍê³É¡£
²âÊÔ·½·¨ÖÐÓõĵ½À©Õ¹·½·¨¿ÉÒÔ¼ûÎÄÕÂ×îºóһС½Ú¡£
¶ÔÓÚÐèÒªÇåÀí·ÖÅä×ÊÔ´µÄ²âÊÔÀ࣬¿ÉÒÔʵÏÖIDisposable½Ó¿Ú²¢ÊµÏÖÏàÓ¦Dispose·½·¨£¬xUnit.net½«¸ºÔ𽫹¹Ô캯ÊýÖзÖÅä¶ÔÏóµÄÊÍ·Å¡£
xUnit.netÿ´ÎÖ´ÐвâÊÔ·½·¨Ê±£¬¶¼ÊÇʵÀý»¯Ò»¸ö²âÊÔÀàµÄжÔÏ󣬱ÈÈçÖ´ÐÐÉÏÃæµÄ²âÊÔÀàÖеÄÁ½¸ö²âÊÔ²âÊÔ·½·¨»áÖ´ÐвâÊÔÀàµÄ¹¹Ô캯ÊýÁ½´Î£¨DisposeÒ²»áÖ´ÐÐÁ½´Î±£Ö¤·ÖÅäµÄ¶ÔÏó±»ÊÍ·Å£©¡£ÕâÖÖÉèÖÃʹÿ¸ö²âÊÔ·½·¨¶¼ÓÐÒ»¸ö¸É¾»µÄÉÏÏÂÎÄÀ´Ö´ÐУ¬²»Í¬²âÊÔ·½·¨Ê¹ÓÃͬÃûµÄ²âÊÔÀà³ÉÔ±²»»á²úÉú³åÍ»¡£
3.±ÜÃâÖØ¸´³õʼ»¯
Èç¹û²âÊÔ·½·¨¿ÉÒÔ¹²ÓÃÏàͬµÄ²âÊÔÀà³ÉÔ±£¬»òÊdzöÓÚÌá¸ß²âÊÔÖ´ÐÐËÙ¶È¿¼ÂÇÎÒÃÇÏ£ÍûÔÚÖ´ÐÐÀàÖвâÊÔ·½·¨Ê±³õʼ»¯´úÂëÖ»Ö´ÐÐÒ»´Î£¬¿ÉÒÔʹÓÃÏÂÃæ½éÉܵķ½·¨À´¹²Ïíͬһ·Ý²âÊÔÉÏÏÂÎÄ£¨²âÊÔÀàµÄ¶ÔÏ󣩣º
Ê×ÏÈʵÏÖÒ»¸öFixtureÀàÓÃÀ´Íê³ÉÐèÒª¹²ÏíµÄ¶ÔÏóµÄ³õʼ»¯ºÍÊͷʤ×÷£º
public class DbContextFixture:
IDisposable
{
private const string TestDatabaseConnectionName
= "DefaultConnectionTest";
public readonly IDbContext Context;
public DbContextFixture()
{
Context = new MyObjectContext(TestDatabaseConnectionName);
}
public void Dispose()
{
Context.Dispose();
}
} |
ÏÂÃæÊÇÖØµã£¬Çë×¢ÒâÔõÑùÔÚ²âÊÔÀàÖÐʹÓÃÕâ¸öFixture£º
public class
EFRepositoryByFixtureTests : IClassFixture<DbContextFixture>
{
private readonly IDbContext _context;
private readonly IRepository<User> _repository;
public EFRepositoryByFixtureTests(DbContextFixture
dbContextFixture)
{
_context = dbContextFixture.Context;
_repository = new EfRepository<User>(_context);
}
//²âÊÔ·½·¨ÂÔ...
} |
²âÊÔÀàʵÏÖÁËIClassFixture<>½Ó¿Ú£¬È»ºó¿ÉÒÔͨ¹ý¹¹Ô캯Êý×¢Èë»ñµÃÇ°ÃæµÄFixtureÀàµÄ¶ÔÏó£¨Õâ¸ö×¢ÈëÓÉxUnit.netÀ´Íê³É£©¡£
ÕâÑùËùÓвâÊÔ·½·¨½«¹²Ïíͬһ¸öFixture¶ÔÏ󣬼´DbContextÖ»±»³õʼ»¯Ò»´Î¡£
³ýÁËÔÚͬһ¸öÀàµÄ²âÊÔ·½·¨Ö®¼ä¹²Ïí²âÊÔÉÏÏÂÎÄ£¬Ò²¿ÉÒÔÔÚ¶à¸ö²âÊÔÀàÖ®¼ä¹²Ïí²âÊÔÉÏÏÂÎÄ£º
public class
DbContextFixture : IDisposable
{
private const string TestDatabaseConnectionName
= "DefaultConnectionTest";
public readonly IDbContext Context;
public DbContextFixture()
{
Context = new GalObjectContext(TestDatabaseConnectionName);
}
public void Dispose()
{
Context.Dispose();
}
}
[CollectionDefinition("DbContext Collection")]
public class DbContextCollection : ICollectionFixture<DbContextFixture>
{
} |
FixtureÀàºÍ֮ǰһģһÑù£¬Õâ´Î¶àÁËÒ»¸öCollection½áβµÄÀàÀ´ÊµÏÖÒ»¸öÃûΪICollectionFixture<>½Ó¿ÚµÄÀà¡£Õâ¸öÀàûÓдúÂëÆä×îÖ÷ÒªµÄ×÷ÓõÄÊdzÐÔØÕâ¸öCollectionDefinition
Attribute£¬Õâ¸öÌØÐÔµÄÃû×ַdz£ÖØÒª¡£
À´¿´Ò»ÏÂÔÚ²âÊÔÀàÖÐÔõôʹÓãº
[Collection("DbContext
Collection")]
public class EFRepositoryCollectionTest1
{
private readonly IDbContext _context;
private readonly IRepository<User> _repository;
public EFRepositoryCollectionTest1(DbContextFixture
dbContextFixture)
{
_context = dbContextFixture.Context;
_repository = new EfRepository<User>(_context);
}
//²âÊÔ·½·¨ÂÔ...
}
[Collection("DbContext Collection")]
public class EFRepositoryCollectionTest2
{
private readonly IDbContext _context;
private readonly IRepository<User> _repository;
public EFRepositoryCollectionTest2(DbContextFixture
dbContextFixture)
{
_context = dbContextFixture.Context;
_repository = new EfRepository<User>(_context);
}
//²âÊÔ·½·¨ÂÔ...
} |
ÔÚ²âÊÔÀàÉÏͨ¹ýCollectionÌØÐÔ±ê¼ÇÕâ¸ö²âÊÔÀàÐèÒªFixture£¬×¢ÒâCollectionÌØÐÔ¹¹Ô캯ÊýµÄ²ÎÊýÓëCollectionDefinitionÌØÐÔ¹¹Ô캯ÊýµÄ²ÎÊý±ØÐëÍêȫƥÅ䣬xUnit.netͨ¹ýÕâ¸öÀ´½øÐйØÁª¡£±ê¼ÇÉÏ[Collection]ºó¾Í¿ÉÒÔͨ¹ý¹¹Ô캯Êý×¢Èë»ñµÃFixture¶ÔÏóÁË£¬Õâ¸öÓë֮ǰ¾ÍÊÇÏàͬµÄÁË¡£
Óм¸¸ö²âÊÔÀà¾Í±ê¼¸¸ö[Collection]£¬ÕâЩ²âÊÔÀཫ¹²ÏíÏàͬµÄFixture¶ÔÏó¡£
Èç¹ûÎÒÃǰÑDbContextCollectionµÄʵÏָijɣº
[CollectionDefinition("DbContext
Collection")]
public class DbContextCollection : IClassFixture<DbContextFixture>
{
} |
½á¹ûÊÇEFRepositoryCollectionTest1ºÍEFRepositoryCollectionTest2ÓµÓв»Í¬µÄFixture¶ÔÏ󣬵«ÔÚËüÃÇÀàµÄ·¶Î§ÄÚÕâ¸öFixtureÊǹ²ÏíµÄ¡£
4.Òì²½·½·¨²âÊÔÖ§³Ö
Òì²½±à³ÌÔÚC#ºÍ.NETÖбäµÃÔÀ´Ô½Á÷ÐУ¬¿âÖкܶ෽·¨¶¼Ôö¼ÓÁËAsync°æ±¾£¬ÓÐЩÐÂÔö¼ÓµÄ¿âÉõÖÁÖ»ÓÐAsync°æ±¾µÄ·½·¨£¨ÒÔUWPΪ´ú±í£©¡£¶ÔÒì²½·½·¨µÄ²âÊÔÒ²Ô½À´Ô½ÖØÒª£¬xUnit.net´Óij¸ö°æ±¾£¨ÍüÁËÊÇÄĸöÁË£©Æð¿ªÊ¼Ö§³ÖÒì²½·½·¨²âÊÔ¡£ÐèÒªµÄ¸Ä¶¯·Ç³£¼òµ¥¾ÍÊǰѷµ»ØvoidµÄ²âÊÔ·½·¨¸Ä³É·µ»ØTask²¢Ìí¼Óasync¹Ø¼ü×Ö±äΪÒì²½·½·¨£¬ÕâÑùxUnit.net¾ÍÄÜÕýÈ·µÄ´Ó±»²âÊÔµÄÒì²½·½·¨»ñȡֵ²¢Íê³É²âÊÔ¡£
±ÈÈç¼ÓÈë֮ǰÓùýµÄIRepositoryÖжàÁËÒ»¸öÒì²½·½·¨GetByIdAsync£¬Òª¶ÔÕâ¸ö·½·¨½øÐе¥Ôª²âÊÔ£º
Task<T>
GetByIdAsync(object id); |
Òì²½µÄ²âÊÔ·½·¨ÈçÏ£º
[Fact]
public async Task Test_get_async()
{
var userId = 1;
var user = await _repository.GetByIdAsync(userId);
Assert.True(user.UserName.Length>0);
} |
»ù±¾ÉÏÎÒÃÇÔõôȥдÒì²½·½·¨¾ÍÔõôȥдÒì²½²âÊÔ·½·¨¡£
5.¸ø²âÊÔ·½·¨´«ÈëϵÁвÎÊý
ÕâһС²¿·ÖÊÇÎÄÕ¿ìÍê³Éʱ£¬¶ÁÁËÏÂxUnitÎĵµ²¹³äÉϵģ¬ÔÚÕâ֮ǰȫȻ²»ÖªµÀxUnit.net»¹ÓÐÕâô¸ö¹¦ÄÜ£¬¿´À´¶àд²©¿Í¿ÉÒÔ°ïÖúÍêÉÆÖªÊ¶µãÖеÄ©¶´£¬´ó¼Ò¹²Ãã¡£
³ýÁ˳£ÓõÄ[Fact]£¬xUnit»¹Ìṩһ¸öÃûΪ[Theory]µÄ²âÊÔAttribute¡£xUnitÎĵµºÜ¼òÃ÷µÄ½âÊÍÁ½ÕߵIJ»Í¬£º
FactËù²âÊԵķ½·¨½á¹û×ÜÊÇÒ»Öµģ¬¼´ËüÓÃÀ´²âÊÔ²»±äµÄÌõ¼þ¡£
Theory²âÊԵķ½·¨¶ÔÒ»¸öÌØ¶¨¼¯ºÏÖеÄÊý¾Ý²âÊÔ½á¹ûÎªÕæ¡£
Ïë²»³öÆäËüÀý×Ó£¨ÎÒµÄȷûÓùý£©£¬¾Í¸ø³ö¹Ù·½µÄÀý×Ó°É¡£
±»²â·½·¨£º
//ÅжÏÒ»¸öÊýÊÇ·ñÎªÆæÊý
bool IsOdd(int value)
{
return value % 2 == 1;
} |
²âÊÔ·½·¨£º
[Theory]
[InlineData(3)]
[InlineData(5)]
[InlineData(6)]
public void MyFirstTheory(int value)
{
Assert.True(IsOdd(value));
} |
²âÊÔ½á¹û£º

ͼ5
¶ÔÓÚ²âÊÔÊý¾Ý¼¯ºÏÖеÄ6²»ÊÇÆæÊý£¬ËùÒÔ²âÊÔʧ°Ü¡£
ËäȻֻÓÐÒ»¸ö²âÊÔ·½·¨£¬µ«xUnit»áÕë¶ÔÿÌõµÄInlineData´«ÈëµÄÊý¾ÝÖ´ÐÐÒ»´Î²âÊÔ£¬ÕâÑù¿ÉÒÔºÜÈÝÒ׿´³öÊÇÄÄÒ»ÌõInlineData³öÁËÎÊÌâ¾ÍÈçͼ5Ëùʾ¡£
Ð޸IJâÊÔ¼¯£º
[Theory]
[InlineData(3)]
[InlineData(5)]
[InlineData(7)]
public void MyFirstTheory(int value)
{
Assert.True(IsOdd(value));
}
|
ÕâÑù²âÊԾͿÉÒÔ˳Àûͨ¹ýÁË¡£

ͼ6
6.Mock³õ´ÎµÇ³¡
»¹ÊÇÒÔʵ¼ÊÏîÄ¿Öг£¼ûµÄ³¡¾°À´½éÉÜÐèҪʹÓÃMockµÄ³¡¾°£¬ÈçÏÖÔÚÓÐÒ»¸öUserService£¨Æª·ùÔÒòֻչʾ²¿·Ö£©£º
public class UserService
: IUserService
{
private readonly IRepository<User> _userRepository;
public UserService(IRepository<User> userRepository)
{
_userRepository = userRepository;
}
public User GetUserById(int userId)
{
return _userRepository.GetById(userId);
}
public void Create(User user)
{
_userRepository.Insert(user);
}
public void Update(User user)
{
_userRepository.Update(user);
}
public void Delete(User user)
{
...
}
} |
Òª²âÊÔÕâ¸öUserService²»Ãâ»á¶ÔIRepository²úÉúÒÀÀµ£¬ÓÉÓÚÔÚ֮ǰµÄ²âÊÔÖп´µ½RepositoryÒѾ¹ýÍêÉÆµÄ²âÊÔ£¬ËùÒÔÔÚ²âÊÔUserServiceµÄʱºò¿ÉÒÔʹÓÃÒ»¸öÓëRepositoryÓÐÏàͬ½Ó¿ÚµÄStubÀ࣬ÈçRepositoryStub£¬À´´úÌæEFRepository¹©UserServiceʹÓã¬Õâ¸öÀ಻½øÐÐʵ¼ÊµÄÊý¾Ý·ÃÎÊ£¬Ö»Êǰ´ÕÕÎÒÃǵIJâÊÔÆÚÍûͨ¹ýÓ²±àÂëµÄ·½Ê½·µ»ØÒ»Ð©Öµ¡£µ«ÍùÍù´óÐÍÏîÄ¿ÖÐÓгɰÙÉÏǧµÄÀàÐèÒªÓжÔÓ¦µÄMockÀàÓÃÓÚµ¥Ôª²âÊÔ£¬ÊÖдÕâЩxxxMockÀàÊÇÒ»¸öºÜ´óµÄ¹¤×÷¡£ÓÚÊÇMock¿ò¼Üµ®ÉúÁË¡£
Mock¿ò¼Ü£¨Î¢Èí³Æ×öFakes¿ò¼Ü£¬Ó¦¸Ã¾ÍÊÇÒ»¸ö¶«Î÷£©µÄ×÷ÓþÍÊÇÁé»î·½±ãµÄ¹¹Ôì³öÕâÖÖMockÀàµÄʵÀý¹©µ¥Ôª²âÊÔ·½·¨Ê¹Óá£
Mock£¬StubÕâÁ½ÕßµÄÇø·ÖÀÏÍâÃǺÃÏñÒ»Ö±ÔÚÌÖÂÛ¡£´ó¸Å¾ÍÊÇ£¬Stub±íʾÐéÄâµÄ¶ÔÏóÖдæÔÚÕâЩStub·½·¨Ê¹±»²âÊÔ·½·¨¿ÉÒÔÕý³£¹¤×÷£¬¶øMock²»µ«ÊÇÐéÄâ¶ÔÏóÖÐÐèÒªÌṩµÄ·½·¨£¬»¹¿ÉÒÔÑéÖ¤±»²â¶ÔÏóÊÇ·ñÓëMock·¢ÉúÁ˽»»¥¡£Mock¿ÉÄÜÊDzâÊÔ²»Í¬¹ýµÄÔÒò£¬µ«Stub²»»áÊÇ¡£Í¨¹ýÎÄÖÐRhino
MocksµÄÀý×Ó¿ÉÒÔ×ÐϸÌå»áÕâÁ½¸ö¸ÅÄîµÄ²»Í¬¡£
±ÈÈçÎÒÃDzâÊÔÏÂÉÏÃæ´úÂëÖеÄGetUserById·½·¨£¨ËäÈ»Õâ¸ö·½·¨ºÜ¼òµ¥£¬Êµ¼ÊÏîÄ¿ÖÐûÓвâÊԵıØÒª£¬µ«×÷ΪÀý×Ó»¹ÊǺܺÏÊʵġ££©
[Fact]
public void Test_GetUser()
{
var userRepository = MockRepository.GenerateStub<IRepository<User>>();
userRepository.Stub(ur => ur.GetById(1)).Return(new
User() { UserName = "wangwu" });
var userService = new UserService(userRepository);
var userGet = userService.GetUserById(1);
Assert.Equal("wangwu", userGet.UserName);
} |
Õâ¿ÉÄÜÊÇʹÓÃMock¿ò¼Ü×î¼òµ¥µÄÀý×ÓÁË£¬GenerateStub·½·¨Éú³ÉÒ»¸ö¡±×®¡°¶ÔÏó£¬È»ºóʹÓÃStub·½·¨Ìí¼ÓÒ»¸ö¡±×®¡°·½·¨£¬Ê¹ÓÃÕâ¸ö×®¶ÔÏóÀ´¹¹ÔìUserService¶ÔÏ󣬺ÜÏÔÈ»²âÊÔ»á˳Àûͨ¹ý¡£
Àý×ÓÖÐStub·½·¨ÏÔʽҪÇó½ÓÊÕ1×÷Ϊ²ÎÊý£¨¼´Èç¹ûÎÒÃǸøGetUserById´«Èë·Ç1µÄÊý×Ö²âÊÔÎÞ·¨Í¨¹ý£©£¬µ«±»²â·½·¨ÆäʵÊÇ¿ÉÒÔ´«ÈëÈÎÒâ²ÎÊýµÄ¡£¿ÉÒÔͨ¹ýRhino
MockÌṩµÄÇ¿´óµÄArg<T>À´¸Ä±äһϲÎÊýÔ¼Êø£º
userRepository.Stub(ur
=> ur.GetById(Arg<int>.Is.Anything)).Return(new
User() { UserName = "wangwu" }); |
ÕâÑù¾Í¿ÉÒÔ¸ø±»²â·½·¨´«ÈëÈÎÒâÕûÊý²ÎÊý£¬¸ü·ûºÏ²âÊÔÓïÒå¡£Arg<T>ÀàÌṩÁ˸÷ÖÖ¸÷Ñù¶Ô²ÎÊýÔ¼ÊøµÄº¯Êý£¬ÒÔ¼°Ò»¸ö¼¸ºõÎÞËù²»ÄܵÄMatches·½·¨£¬ºóÎÄ»¹ÓÐÓнéÉÜ¡£
ÉÏÃæÓõ½µÄÖ»ÊÇMock¿ò¼ÜÒ»²¿·Ö×÷Óã¬Mock¿ò¼Ü¸üÉñÆæµÄµØ·½½«ÔÚÏÂһС½Ú½éÉÜ¡£
7.Mock´óÏÔÉíÊÖ - ²âÊÔûÓÐÏÔʽ·µ»ØÖµµÄ·½·¨
ǰÎĽéÉܵĴ󲿷ÖÄÚÈÝAssert¶¼ÊÇÓÃÀ´Åжϱ»²âÊÔ·½·¨µÄ·µ»ØÖµ¡£Êµ¼ÊÏîÄ¿Öл¹ÓÐÐí¶àûÓзµ»ØÖµµÄ·½·¨Ò²ÐèÒªÎÒÃÇͨ¹ý²âÊÔÀ´±£Ö¤ÆäÖÐÂß¼µÄÕýÈ·ÐÔ¡£ÕâЩûÓзµ»ØÖµµÄ·½·¨ÓпÉÄÜÊǽ«Êý¾Ý±£´æµ½Êý¾Ý¿â£¬ÓпÉÄÜÊǵ÷ÓÃÁíÒ»¸ö·½·¨À´Íê³ÉÏà¹Ø¹¤×÷¡£
¶ÔÓÚ½«Êý¾Ý±£´æµ½Êý¾Ý¿âµÄÇé¿ö֮ǰµÄ²âÊÔÓнéÉÜÕâÀï²»ÔÙ׸Êö¡£¶ÔÓÚµ÷ÓÃÁíÒ»¸ö·½·¨£¨ÕâÀïÖ¸µ÷ÓÃÁíÒ»¸öÀàµÄ·½·¨»òµ÷ÓÃͬһ¸öÀàÖз½·¨µÄ²âÊÔÏÂһС½Ú½éÉÜ£©µÄÇé¿ö£¬ÎÒÃÇͨ¹ýMock¿ò¼ÜÌṩµÄAssert·½·¨À´±£Ö¤ÁíÒ»¸öÀàµÄ·½·¨È·Êµ±»µ÷Óá£
ÕâÀïÒÔ±£´æÓû§·½·¨ÎªÀýÀ´¿´Ò»Ï²âÊÔÈçºÎ±àд£º
public void
Create(User user)
{
_userRepository.Insert(user);
} |
Èç´úÂ룬Õâ¸ö·½·¨Ã»Óзµ»ØÖµ£¬Ê¹ÓÃ֮ǰµÄAssert·½·¨ÎÞ·¨ÑéÖ¤·½·¨ÕýÈ·Ö´ÐС£ÓÉÓÚµ¥Ôª²âÊÔÖеÄuserRepositoryÊÇMock¿ò¼ÜÉú³ÉµÄ£¬¿ÉÒÔ½èÖúRhino
MocksÌṩµÄ¹¦ÄÜÀ´ÑéÖ¤Õâ¸ö·½·¨È·Êµ±»µ÷Óò¢´«ÈëÁËÇ¡µ±µÄ²ÎÊý¡£
[Fact]
public void Test_Create_User()
{
var userRepository = MockRepository.GenerateMock<IRepository<User>>();
userRepository.Expect(ur => ur.Insert(Arg<User>.Is.Anything));
var userService = new UserService(userRepository);
userService.Create(new User() {UserName = "zhangsan"});
userRepository.VerifyAllExpectations();
} |
Õâ¸ö²âÊÔ´úÂëºÍÉÏһС½Ú²âÊÔ´úÂ벻֮ͬ´¦ÔÚÓÚʹÓÃGenerateMockºÍExcept·½·¨Ìæ´úÁËGenerateStubºÍStub·½·¨£¬Ç°ÕßÓÃÓÚÖ¸¶¨Ò»¸ö¿ÉÒÔ±»ÑéÖ¤µÄÆÚÍû£¬¶øºóÕßÖ»ÊÇÌṩһ¸öÐéÄâµÄ×®¡£ÔÚ´úÂëµÄ×îºóͨ¹ýVerifyAllExpectations·½·¨ÑéÖ¤ËùÓÐÆÚÍû¶¼±»Ö´ÐС£Ö´ÐвâÊÔûÓÐÒâÍâµÄ»°²âÊÔ¿ÉÒÔÕý³£Í¨¹ý¡£
¸øExpectÖ¸¶¨µÄlambda±í´ïʽÖеÄInsert·½·¨½ÓÊÜArg<User>.Is.Anything×÷Ϊ²ÎÊý£¬ÕâÕý·ûºÏ±»²âÊÔº¯ÊýµÄÒªÇó¡£Èç¹ûCreateº¯ÊýÖÐûÓе÷ÓÃIRepositoryµÄInsertº¯Êý£¬²âÊÔÒ²»áʧ°Ü£º

ͼ7
ÕâÊÇÑéÖ¤º¯Êý±»Ö´ÐеÄÒ»ÖÖ·½·¨£¬»¹ÓÐÁíÒ»ÖÖµÈЧµÄ·½·¨£¬ÇÒºóÕßÔÚÍâ¹ÛÉϸü·ûºÏ֮ǰÌáµ½µÄµ¥Ôª²âÊÔµÄAAAģʽ£º
[Fact]
public void Test_Create_User()
{
var userRepository = MockRepository.GenerateMock<IRepository<User>>();//ÕâÖÖ·½·¨ÖУ¬ÕâÀïʹÓÃGenerateMockºÍGenerateStub¶¼¿ÉÒÔ
var userService = new UserService(userRepository);
userService.Create(new User() {UserName = "zhangsan"});
userRepository.AssertWasCalled(ur => ur.Insert(Arg<User>.Is.Anything));
} |
Èç´úÂëËù¼û£¬Õâ¶Î²âÊÔ´úÂëûÓÐʹÓÃExpectÉèÖÃÆÚÍû£¬¶øÊÇͨ¹ýAssertWasCalledÀ´ÑéÖ¤Ò»¸öº¯ÊýÊÇ·ñ±»µ÷Óá£
ÉÏÃæ´ó²¿·ÖÀý×Ó¶¼Ê¹ÓÃÁËRhino MocksµÄGenerateMock<T>()ºÍGenerateStub<T>()¾²Ì¬·½·¨¡£Rhino
Mocks»¹Í¨¹ýMockRepository¶ÔÏóµÄʵÀý·½·¨DynamicMock<T>()ºÍStub<T>()ÌṩÁËÏàͬµÄ¹¦ÄÜ¡£ÕâÁ½ÕßµÄ×îÖ÷񻂿±ðÊÇ£¬¶ÔÓÚExceptµÄÑéÖ¤£¬Ç°ÕßÖ»ÄÜÔÚ¾²Ì¬·½·¨·µ»ØµÄ¶ÔÏóÉÏ·Ö±ðµ÷ÓÃVerifyAllExpectations()·½·¨½øÐÐÑéÖ¤£¬¶øºóÕß¿ÉÒÔÔÚMockRepository¶ÔÏóÉϵ÷ÓÃVerifyAll()ÑéÖ¤MockRepositoryÖÐËùÓеÄExcept¡£
8.²âÊÔÀàÄÚ²¿·½·¨µ÷ÓÃ
ʵ¼Ê²âÊÔÖл¹³£³£»áÓöµ½Ò»¸ö·½·¨µ÷ÓÃÏàͬÀàÖÐÁíÒ»¸ö·½·¨µÄÕâÖÖÐèÒª²âÊÔµÄÇé¿ö£¬ÎªÁ˺ÃÃèÊö£¬¼ÙÉèÊÇCÀàÖеÄA·½·¨µ÷ÓÃÁËB·½·¨¡£
ÏÈ˵AºÍB¶¼ÊÇpublic·½·¨µÄÇé¿ö£¬ÕýÈ·µÄ²âÊÔ·½·¨Ó¦¸ÃÊÇ·Ö±ð²âÊÔA£¬B·½·¨£¬¶ÔÓÚAµÄ²âÊÔʹÓÃMock¿ò¼ÜÉú³ÉÒ»¸öBµÄStub·½·¨¡£
ÏÈ¿´Ò»ÏÂÓÃÀ´Õ¹Ê¾µÄ´ý²â·½·¨£º
public void
Create(User user)
{
if (IsUserNameValid(user.UserName))
_userRepository.Insert(user);
}
public virtual bool IsUserNameValid(string userName)
{
//¼ì²éÓû§ÃûÊÇ·ñ±»Õ¼ÓÃ
Debug.WriteLine("IsUserNameValid called");
return true;
} |
ÔÚ´´½¨Óû§Ö®Ç°ÐèÒªÑéÖ¤Óû§ÃûÊÇ·ñ¿ÉÓã¬Îª´ËÌí¼ÓÁËÒ»¸öIsUserNameValid·½·¨¡£ÎªÁËÑÝʾÕâ¸ö·½·¨±»±ê¼ÇΪpublic¡£ÖµµÃ×¢ÒâÊÇÕ⻹ÊÇÒ»¸övirtual·½·¨£¬ÒòΪÏÂÎÄÎÒÃÇÒªÓÃRhino
MocksÉú³ÉÕâ¸ö·½·¨µÄÒ»¸öÆÚÍû£¬µ±ÓÃRhino MocksÉú³É·½·¨µÄÆÚÍûʱ£¬Èç¹û·½·¨²»ÊôÓÚÒ»¸ö½Ó¿Ú£¬ÔòÕâ¸ö·½·¨±ØÐëÊÇvirtual·½·¨¡£ÏÂÃæÊDzâÊÔ´úÂ룺
[Fact]
public void Test_Create_User_with_innerCall()
{
var userRepository = MockRepository.GenerateMock<IRepository<User>>();
userRepository.Expect(ur => ur.Insert(Arg<User>.Is.Anything));
var userService = MockRepository.GeneratePartialMock<UserService>(userRepository);
userService.Expect(us => us.IsUserNameValid("zhangsan")).Return(true);
userService.Create(new User() { UserName = "zhangsan"
});
userRepository.VerifyAllExpectations();
userService.VerifyAllExpectations();
} |
×îÖØÒªµÄ²¿·Ö¾ÍÊÇͨ¹ýGeneratePartialMock·½·¨Éú³ÉÁËÒ»¸öuserServiceµÄ¶ÔÏó£¬È»ºóÔÚÉÏÃæÉèÖÃÁËIsUserNameValid·½·¨µÄÆÚÍû¡£ÕâÑùUserService¶ÔÏóÖгýÁËIsUserNameValid¶ÔÏóÍ⣬ÆäËü·½·¨¶¼½«Ê¹ÓÃÕæÊµ·½·¨£¬ÕâÑùÎÒÃDzâÊÔµÄCreate·½·¨½«µ÷ÓÃÕæÊµ·½·¨¶øIsUserNameValidÊÇMock¿ò¼ÜÉú³ÉµÄ¡£¾ÍÍê³ÉÁËÎÒÃǵÄÐèÇó¡£
ÉÏÃæ½éÉÜÁËAºÍB¶¼ÊÇpublic·½·¨µÄÇé¿ö£¬Êµ¼ÊÏîÄ¿Öиü³£¼ûµÄÇé¿öÊÇAÊÇpublic·½·¨¶øBÊÇprivate·½·¨£¬¼´IsUserNameValidÊÇÒ»¸öprivate·½·¨£º
private bool
IsUserNameValid(string userName)
{
//¼ì²éÓû§ÃûÊÇ·ñ±»Õ¼ÓÃ
Debug.WriteLine("IsUserNameValid called");
return true;
} |
¶ÔÓÚÕâÖÖÇé¿öÒ»°ã¿ÉÒÔͨ¹ý¶ÔAµÄ²âÊÔͬʱÑéÖ¤BµÄÖ´ÐÐÊÇÕýÈ·µÄ£¬¼´°ÑB×÷ΪAÀ´Ò»Æð²âÊÔ£¬ÒòΪÕâʱºòÎÞ·¨µ¥¶ÀʹÓÃMock¿ò¼ÜÀ´Ä£ÄâB·½·¨¡£ËùÒÔÒ²Òª±£Ö¤ÔÚ²âÊÔ·½·¨Öд«ÈëµÄ²ÎÊý¿ÉÒÔÈÃAºÍB¶¼Õý³£Ö´ÐС£
Èç¹ûprivate·½·¨·Ç³£¸´ÔÓ£¬Ò²¿ÉÒÔ¶Ôprivate·½·¨µ¥¶À²âÊÔ¡£
¶ÔÓÚprivate·½·¨µÄ²âÊÔû·¨Ïñ²âÊÔpublic·½·¨ÄÇÑùʵÀý»¯Ò»¸ö¶ÔÏóÈ»ºóµ÷Ó÷½·¨¡£ÐèÒª½èÖúÒ»¸ö¹¤¾ßÀ´µ÷ÓÃprivate·½·¨£¬¶Ô´Ë΢ÈíÔÚMicrosoft.VisualStudio.QualityTools
.UnitTestFramework.dllÌṩÁËÒ»¸öPrivateObjectÀà¿ÉÒÔÍê³ÉÕâ¸ö¹¤×÷¡£Õâ¸ödllλÓÚC:\Program
Files (x86)\Microsoft Visual Studio 14.0 \Common7\IDE
\PublicAssemblies\£¨¸ù¾Ývs°æ±¾²»Í¬ÓÐËù²»Í¬£©Ï£¬ÐèÒªÊÖ¹¤Ìí¼ÓÒýÓá£
Èç±»²â·½·¨ÊÇÒ»¸öprivate·½·¨£º
private bool
IsUserNameValid(string userName)
{
//¼ì²éÓû§ÃûÊÇ·ñ±»Õ¼ÓÃ
Debug.WriteLine("IsUserNameValid called");
return true;
} |
²âÊÔ´úÂë¿ÉÒÔÕâÑùд£º
[Fact]
public void Test_IsUserNameValid()
{
var userService = new UserService(null);
var userServicePrivate = new PrivateObject(userService);
var result = userServicePrivate.Invoke("IsUserNameValid","zhangsan");
Assert.True((bool)result);
} |
¼´Ê¹ÓÃPrivateObject°Ñ±»²âÀà°üÆðÀ´£¬È»ºóͨ¹ýInvoke·½·¨µ÷ÓÃprivate·½·¨¼´¿É¡£
9.Rhino MocksµÄ¸ß¼¶¹¦ÄÜ
ÓÐÁËǰÎĺÍRhino MocksµÄ½Ó´¥µÄ»ù´¡£¬ÕâһС½ÚÀ´¿´Ò»ÏÂRhino MocksµÄһЩ¸ß¼¶¹¦ÄÜ¡£
ArgʵÏÖ²ÎÊýÔ¼Êø
ÔÚǰÎÄÎÒÃÇÒѾÌå»áµ½ÁËArg<T>µÄÇ¿´ó£¬Arg<T>.Is.Anything×÷Ϊ²ÎÊý¾Í¿ÉÒÔÖ¸¶¨Stub·½·¨½ÓÊÜÖ¸¶¨ÀàÐ͵ÄÈÎÒâ²ÎÊý¡£Arg»¹¿ÉÒÔ½øÐиü¶àµÄ²ÎÊýÏÞÖÆ£¬µ±±»²âÊÔ·½·¨¸øÆÚÍû·½·¨´«ÈëµÄ²ÎÊý²»·ûºÏ²ÎÊýÔ¼ÊøÊ±£¬ÑéÖ¤ÆÚÍû»áʧ°Ü×îÖÕ½«µ¼Ö²âÊÔ²»Í¨¹ý¡£ÏÂÃæµÄ±í¸ñÀ´×ÔRhino
Mocks¹Ù·½Îĵµ£¬ÆäÖÐÁгöÁËArgÖ§³ÖµÄ´ó²¿·ÖÔ¼Êø¡££¨²©Ö÷·Òë²¢°´ÕÕ×îеÄ3.6.1°æÕûÀíÁËÏ£©
Arg<T>.Is |
|
|
Equal(object)
NotEqual(object) |
²ÎÊýÏàµÈ»ò²»µÈ |
|
GreaterThan(object)
GreaterThanOrEqual(object)
LessThan(object)
LessThanOrEqual(object)
|
´óÓÚ£¬´óÓÚµÈÓÚ£¬Ð¡ÓÚ£¬Ð¡ÓÚµÈÓÚ±È½Ï |
|
Same(object)
NotSame(object)
|
±È½ÏÒýÓÃÊÇ·ñÏàͬ |
|
Anything
|
ÈÎÒâ²ÎÊý |
|
Null
NotNull
|
²ÎÊýΪ¿Õ»ò²»Îª¿Õ |
|
TypeOf
|
²ÎÊýΪ·ºÐͲÎÊýÖ¸¶¨µÄÀàÐÍ |
Arg<T>.List |
|
|
OneOf(IEnumerable)
|
È·¶¨²ÎÊýÊÇÖ¸¶¨¼¯ºÏÖеÄÒ»¸ö |
|
Equal(IEnumerable)
|
²ÎÊýÁбíÓëÖ¸¶¨ÁбíÏàͬ |
|
Count(AbstractConstraint)
|
È·¶¨²ÎÊý¼¯ºÏÓÐÖ¸¶¨ÊýÁ¿µÄ·ûºÏÔ¼ÊøµÄÔªËØ |
|
Element(int, AbstractConstraint)
|
²ÎÊý¼¯ºÏÖÐÖ¸¶¨Î»ÖõÄÔªËØ¸´ºÏÒ»¸öÔ¼Êø |
|
ContainsAll(IEnumerable)
|
È·¶¨²ÎÊý¼¯ºÏ°üº¬ËùÓеÄÖ¸¶¨ÔªËØ |
|
IsIn(object)
|
¶¨Ö¸¶¨ÔªËØÊôÓÚ²ÎÊý¼¯ºÏ£¨²ÎÊýÐèҪΪIEnumerable£© |
Arg<T&ggt;.Ref() |
Ö¸¶¨ref²ÎÊý |
Arg<T>.Out() |
Ö¸¶¨out²ÎÊý |
Arg.Text |
|
|
StartsWith(string)
EndsWith(string)
Contains(string)
|
²ÎÊý×Ö·û´®ÒÔÖ¸¶¨×Ö·û´®¿ªÊ¼»òÒÔÖ¸¶¨×Ö·û´®½áÊø»ò°üº¬Ö¸¶¨×Ö·û´® |
|
Like(string regex)
|
²ÎÊýÆ¥ÅäÖ¸¶¨ÕýÔò±í´ïʽ |
Arg.Is() |
Arg<T>.Is.Equal()µÈ¼Û |
Arg<T>.Matches() |
|
|
Argt<T>.Matches (Expression)
|
²ÎÊýÆ¥ÅäÒ»¸ölambda±í´ïʽָ¶¨µÄÔ¼Êø |
|
Argt<T>.Matches (AbstractConstraint)
|
ÓÃÓÚ²»Ö§³ÖlambdaµÄC#°æ±¾£¬ÒÔÄÚÖõÄÔ¼ÊøÀàÐÍÖ¸¶¨²ÎÊýÔ¼Êø |
±íÖд󲿷ַ½·¨ºÍxUnit.netÖ§³ÖµÄAssertºÜÀàËÆ¡£ÖصãÀ´¿´Ò»ÏÂÆäÖÐ×îÇ¿´óµÄMatches·½·¨£º
userRepository.Expect(ur
=> ur.Insert(Arg<User>.Matches(u=>
u.UserName.Length>2 && u.UserName.Length<12&&
u.Birthday>DateTime.Now.AddYears(-120)&&
Regex.IsMatch(u.QQ,"^\\d[5,15]#")))); |
Õâ¸ö¸´ÔÓµÄMatches·½·¨²ÎÊýÏÞÖÆÁËÆÚÍûº¯Êý½ÓÊܵIJÎÊý·ûºÏһЩÁÐÌõ¼þ¡£
WhenCalled--ÁíÒ»¸ö¡±bug¡°°ãµÄ´æÔÚ
ÔÚStub¡¢ExpectµÈ·½·¨µÄµ÷ÓÃÁ´ÉÏÓÐÒ»¸öÃûΪWhenCalledµÄ·½·¨£¬ËüÓÃÀ´Ö¸¶¨µ±×®·½·¨»òÆÚÍû·½·¨±»Ö´ÐÐʱËùÖ´ÐеIJÙ×÷¡£ÕâÀïÃæ¿ÉÒԸɺܶàºÜ¶àÊ¡£±ÈÈ磺
userRepository.Stub(ur
=> ur.GetById(Arg<int>.Is.Anything))
.Return(new User() { UserName = "wangwu"
})
.WhenCalled(mi =>
{
//¿ÉÒÔÐÞ¸Ä×®·½·¨µÄ²ÎÊýºÍ·µ»ØÖµ£¬»¹¿ÉÒÔ»ñÈ¡·½·¨ÐÅÏ¢
var args = mi.Arguments;
var methodInfo = mi.Method;
var returnVal = mi.ReturnValue;
//¿ÉÒÔÉèÖñ¾µØ±äÁ¿£¬¹©ÏÂÃæµÄ´úÂëʹÓÃ
getByIdCalled = true;
}); |
¿ÉÒÔÓÃÉèÖõıäÁ¿À´ÅжϷ½·¨×®ÊÇ·ñ±»Ö´ÐУº
Assert.True(getByIdCalled); |
ÅжϷ½·¨Ö´ÐдÎÊý
ÓÐʱºò²»Ö»ÐèÒªÅÐ¶ÏÆÚÍû·½·¨ÊÇ·ñ±»Ö´ÐУ¬»¹ÒªÅжÏÖ´ÐеĴÎÊý¡£Rhino
MocksµÄAssertWasCalled·½·¨µÄÖØÔØÌṩÁËÕâ¸ö¹¦ÄÜ£º
userRepository.AssertWasCalled(ur
=> ur.Insert(Arg<User>.Is.Anything), c=>c.Repeat.Once()); |
ÕâÑùInsert·½·¨Ó¦¸ÃÖ»±»Ö´ÐÐ1´Î²âÊԲſÉÒÔͨ¹ý¡£³ý´Ë»¹ÓÐTwice(),Never(),AtLeastOnce()¼°Times(int)µÈÆäËü·½·¨ÓÃÀ´Ö¸¶¨²»Í¬µÄ´ÎÊý¡£
AssertWasCalledµÚ¶þ¸ö²ÎÊýµÄÀàÐÍAction<T>ÖеÄT£¨¼´lambda±í´ïʽ²ÎÊý£©ÊÇIMethodOptions<T>ÀàÐÍ£¬³ýÁË¿ÉÒÔͨ¹ýRepeatÊôÐԵķ½·¨ÉèÖÃÖ´ÐдÎÊýÔ¼ÊøÍ⻹ÓÐÆäËü·½·¨£¬´ó²¿·Ö·½·¨¿ÉÒÔͨ¹ýÆäËü;¾¶½øÐеȼÛÉèÖ㬻¹ÓÐһЩÒѾ¹ýʱ¾Í²»ÔÙ׸ÊöÁË¡£
10.UWPÖеĵ¥Ôª²âÊÔ
ÉÏÎĵÄÀý×Ó¶¼ÊÇÔÚ.NET Framework 4.5µÄ³ÌÐò¼¯ÖнøÐе쬶ÔÓÚËùÓÐʹÓÃ.NET FrameworkµÄÏîÄ¿ÀàÐͶ¼ÊÊÓ㬱ÈÈçWinform/WPF£¬ASP.NET
MVCµÈµÈ¡£¶ÔÓÚUWPÕâÑù»ùÓÚWindows Runtimeƽ̨µÄ³ÌÐòÓÉÓÚÉÏÎÄʹÓõÄRhinoMocks²»ÄÜÓÃÓÚUWP£¬ËùÒÔÐèÒªÁíÍâѰÕÒ¿ÉÓõÄMock
Framework¡£ÁíÍ⵱ǰ°æ±¾µÄÓÃÓÚResharperµÄxUnit.net Test RunnerÔÚUWP»·¾³²»ÄÜÆô¶¯ÓÃÓÚÖ´ÐвâÊÔ´úÂëµÄ²âÊÔ³ÌÐò£¬ÐèҪʹÓÃxUnit.netÓÃÓÚvsµÄTest
Runner£¬¶øÇÒxUnit.netºÍTest Runner¶¼ÒªÊ¹ÓÃ×îеĵÄ2.1 rc²ÅÄÜÕý³£Æô¶¯Ò»¸ö³ÌÐòÓÃÓÚÖ´ÐвâÊÔ´úÂë¡£
ÔÚUWPÖвâÊÔÏîÄ¿ÊÇÒ»¸ö¿ÉÖ´ÐеijÌÐò£¬²âÊÔ´úÂëÔÚÕâÀïÃæÔËÐС£¶ø²»Ïñ´«Í³.NETÏîÄ¿µÄ²âÊÔÖ»ÐèÒªÒÀ¸½ÓÚÒ»¸öÆÕͨµÄ³ÌÐò¼¯¡£ÔÚUWPÖ´ÐвâÊÔ´úÂëÈç¹ûÉæ¼°µ½ÈçWindows.StorageÕâÖÖÓëÉ豸Ïà¹ØµÄ´úÂëÊÇÐèÒªÒÔÓ¦ÓõÄÉí·ÝÈ¥µ÷Óõġ£ËùÒÔµ¥Ôª²âÊÔÏîÄ¿×÷Ϊһ¸ö¿ÉÖ´ÐÐÏîÄ¿ÊDZØÒªµÄ¡£
ÕÒÀ´ÕÒÈ¥¿ÉÑ¡µÄÕæ²»¶à£¬Ò»¸öÊÇ΢Èí×Ô¼ÒµÄMicrosoft Fakes£¬ÁíÒ»¸öÊÇTelerikµÄJustMock¡£Ç°ÕßûÕÒµ½ÔõôÓã¬·ÅÆú£¨¸Ð¾õ΢ÈívsÀïµÄ²âÊÔ¹¤¾ßÒ»Ö±²»ÔõôºÃÓã©¡£ºóÕßÊÇÒ»¸öÉÌÒµ¹¤¾ß£¨ÓÐÃâ·Ñ°æ£©£¬ÔÝʱÄÃÀ´ÍæÍæ°É¡£ÒòΪǰÎİѸ÷ÖÖ²âÊÔ³¡¾°Ò²¶¼½éÉܵIJ¶àÁË£¬ÕâÀï¾ÍÖ±½Ó¸ø³öÒ»¸öÀý×Ó£¬²¢¿´Ò»ÏÂJustMockÓëRhinoMocksµÄϸ½Ú²»Í¬¡£
±»²â´úÂëºÃÏñÊÇÀ´×Ô¹úÍâÒ»¸ö¿ªÔ´µÄ¿â£¬ÊµÔڼDz»Çå´ÓÄÄ“½è¼ø”À´µÄÁË¡£
public async
Task ClearInvalid()
{
var validExtension = storage.GetFileExtension();
var folder = await storage.GetFolderAsync().ConfigureAwait(false);
var files = await folder.GetFilesAsync();
foreach (var file in files.Where(x => x.FileType
== validExtension))
{
var loadedFile = await storage.LoadAsync<CacheObject> (file.DisplayName).ConfigureAwait(false);
if (loadedFile != null && !loadedFile.IsValid)
await file.DeleteAsync();
}
} |
ÕâÀïÒ»¶ÎUWPÓÃÓÚÇå³ýÎÞЧ»º´æÏÀ´¿´Ò»Ï²âÊÔ´úÂ룺
[Fact]
public async Task Can_ClearInvalid_Success()
{
var fileName = "testfile";
var storage = Mock.Create<IStorageHelper>();
Mock.Arrange(()=> storage.GetFileExtension()).Returns (".json");
var file1 = Mock.CreateLike<StorageFileFake>(sf
=> sf.FileType == ".json" &&
sf.DisplayName == fileName);
var file2 = Mock.CreateLike<StorageFileFake>(sf
=> sf.FileType == ".json" &&
sf.DisplayName == "fileNoInCache");
var file3 = Mock.CreateLike<StorageFileFake> (sf
=> sf.FileType == ".xml" &&
sf.DisplayName == "fileOtherType");
var folder = ApplicationData.Current.LocalFolder; //Partial
Mock
Mock.ArrangeLike< StorageFolder> (folder,sf=>sf.GetFilesAsync() ==
Task.FromResult(new List<IStorageFile>()
{file1,file2,file3} as IReadOnlyList< StorageFile>).AsAsyncOperation());
Mock.ArrangeLike (storage,s => s.GetFolderAsync() ==Task.FromResult(folder));
var cacheObj = Mock.CreateLike<CacheObject>(co
=> co.IsValid == false);
Mock.Arrange(() => storage.LoadAsync<CacheObject> (Arg.AnyString)).OccursAtLeast(2);
Mock.Arrange(() => storage.LoadAsync<CacheObject> (Arg.Is(fileName))).Returns(Task.FromResult(cacheObj));
Mock.Arrange(()=> file1.DeleteAsync()).MustBeCalled();
var cacheManager = new TemporaryCacheManager (storage);
await cacheManager.ClearInvalid();
storage.Assert();
file1.Assert();
} |
StorageÀàÓÉÓÚÌØÊâÔÒò£¨·´ÕýÄÇÖÖʵÏÖÔÚUWPÖеÄÀà¶¼Ò»Ñù£©£¬²»ÄÜͨ¹ýMock.CreateÀ´´´½¨£¬¶øÊÇʹÓÃÁËÒ»¸öÕæÊµµÄ¶ÔÏó£¬È»ºóͨ¹ýJustMock´´½¨Partial
MockµÄ·½Ê½¸øÕâ¸öStorage¶ÔÏóÔö¼ÓһЩÐéÄâµÄ·½·¨¡£
ÖÁÓÚÆäËû·½·¨£¬¿ÉÒÔͨ¹ýÏÂÃæÕâ¸öRhinoMocksºÍJustMock¶Ô±È£¨°´ÎÒµÄÀí½â£¬ÓдíÇëÖ¸Õý£©µÄ±íµÃÖªÓ÷¨£º
RhinoMocks |
JustMock |
MockRepository.GenerateStub<T>()
|
Mock.CreateLike<T>()
|
mock.Stub()
|
Mock.ArrangeLike<T>() |
MockRepository.GenerateMock<T>()
|
Mock.Create<T>()
|
mock.Except()
|
Mock.Arrange()
|
MockRepository .GeneratePartialMock<T>()
|
Ö±½Ó´´½¨ÕæÊµ¶ÔÏ󣬲¢Arrange()Ä£Äâ·½·¨ |
mock.VerifyAllExpectations()
|
mock.Assert() |
Arg<T>
|
Arg |
AssertWasCalled()//Æäʵ²»Ì«Ò»Ñù
|
MustBeCalled() |
c=>c.Repeat.XXX()
|
OccursAtLeast(times) |
µ±Ç°Õâ¶Î²âÊÔ´úÂë²¢²»ÄÜÕýÈ·ÔËÐУ¬ÒòΪ2.1RC°æ±¾µÄxUnit runner for vsºÍJustMock
2015Q2ºÃÏñ²»Ì«¼æÈÝ£¬×ܻᱨÉÙSystem.CoreȱʧɶµÄ´íÎó¡£
11.ͨ¹ýÀ©Õ¹·½·¨½øÐÐAssert
nopCommerceÏîÄ¿Öиøµ¥Ôª²âÊÔ×¼±¸µÄһϵÁÐÀ©Õ¹·½·¨ÓÃÆðÀ´Ò²ºÜ·½±ã£¬¿ÉÒÔ°ÑActºÍAssertºÏ²¢µ½Ò»ÐУ¬Ò»¶¨³Ì¶ÈÉÏÌá¸ß´úÂëµÄ¿É¶ÁÐÔ¡£
Ô´úÂëÊÇ»ùÓÚNUnitµÄ£¬ÎÒ°ÑËüÃǸijÉÁËÖ§³ÖxUnit.netµÄ·ÅÔÚÏÂÃæ¹©ÐèÒªµÄͯЬ²Î¿¼¡£
public static
class TestExtensions
{
public static T ShouldNotBeNull<T>(this
T obj)
{
Assert.NotNull(obj);
return obj;
}
public static T ShouldEqual<T>(this T actual,
object expected)
{
Assert.Equal(expected, actual);
return actual;
}
public static void ShouldEqual(this object actual,
object expected, string message)
{
Assert.Equal(expected, actual);
}
public static Exception ShouldBeThrownBy(this
Type exceptionType, Action testDelegate)
{
return Assert.Throws(exceptionType, testDelegate);
}
public static void ShouldBe<T>(this object
actual)
{
Assert.IsType<T>(actual);
}
public static void ShouldBeNull(this object actual)
{
Assert.Null(actual);
}
public static void ShouldBeTheSameAs(this object
actual, object expected)
{
Assert.Same(expected, actual);
}
public static void ShouldBeNotBeTheSameAs(this
object actual, object expected)
{
Assert.NotSame(expected, actual);
}
public static T CastTo<T>(this object source)
{
return (T)source;
}
public static void ShouldBeTrue(this bool source)
{
Assert.True(source);
}
public static void ShouldBeFalse(this bool source)
{
Assert.False(source);
}
public static void SameStringInsensitive(this
string actual, string expected)
{
Assert.Equal(actual,expected,true);
}
} |
|