Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
C#µ¥Ôª²âÊÔ̾̾¹Û
 
  2575  次浏览      27
 2019-8-23 
 
±à¼­ÍƼö:
±¾ÎÄÀ´×Ô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µÄ´úÂë´°¿ÚÖпÉÒÔ¿´µ½ÕâÑùÕâÑùÒ»¸öСԲȦ£¬µã»÷¾Í¿ÉÒÔ&ldquo;ÔËÐÐ&rdquo;»ò&ldquo;µ÷ʽ&rdquo;Õâ¸ö²âÊÔ·½·¨¡££¨ÆäËü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»Çå´ÓÄÄ&ldquo;½è¼ø&rdquo;À´µÄÁË¡£

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);
}
}
   
2575 ´Îä¯ÀÀ       27
Ïà¹ØÎÄÕÂ

΢·þÎñ²âÊÔÖ®µ¥Ôª²âÊÔ
һƪͼÎÄ´øÄãÁ˽â°×ºÐ²âÊÔÓÃÀýÉè¼Æ·½·¨
È«ÃæµÄÖÊÁ¿±£ÕÏÌåϵ֮»Ø¹é²âÊÔ²ßÂÔ
È˹¤ÖÇÄÜ×Ô¶¯»¯²âÊÔ̽Ë÷
Ïà¹ØÎĵµ

×Ô¶¯»¯½Ó¿Ú²âÊÔʵ¼ù֮·
jenkins³ÖÐø¼¯³É²âÊÔ
ÐÔÄܲâÊÔÕï¶Ï·ÖÎöÓëÓÅ»¯
ÐÔÄܲâÊÔʵÀý
Ïà¹Ø¿Î³Ì

³ÖÐø¼¯³É²âÊÔ×î¼Ñʵ¼ù
×Ô¶¯»¯²âÊÔÌåϵ½¨ÉèÓë×î¼Ñʵ¼ù
²âÊԼܹ¹µÄ¹¹½¨ÓëÓ¦ÓÃʵ¼ù
DevOpsʱ´úµÄ²âÊÔ¼¼ÊõÓë×î¼Ñʵ¼ù