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

1Ôª 10Ôª 50Ôª





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



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Modeler   Code  
»áÔ±   
 
   
 
 
     
   
 ¶©ÔÄ
  ¾èÖú
ÀûÓÃSpec Flow±àд×Ô¶¯»¯ÑéÊÕ²âÊÔ
 
×÷ÕߣºMustafa Saeed Haji Ali À´Ô´£ºInfoQ ·¢²¼ÓÚ 2016-3-24
  4108  次浏览      29
 

¶ÔÑéÊÕ²âÊÔ¡¢Gherkin¼°Spec FlowµÄ½éÉÜ

ÑéÊÕ²âÊÔ»ò¹¦ÄܲâÊÔÊÇÑé֤ϵͳÊÇ·ñÂú×ãÐèÇóµÄÒ»ÖÖ²âÊÔ¡£ÕâЩ²âÊÔ×÷ΪºÚºÐ²âÊÔµÄÒ»ÖÖ£¬ÓëÆäÄÚ²¿¾ßÌåÖ´ÐÐÎ޹ء£ÑéÊÕ²âÊÔÖ»ÊÇÓÃÀ´Ñé֤ϵͳÊÇ·ñ·ûºÏijһÐèÇó¡£

ÏÖÔÚÎÒÃÇÒ»Æð¿´ÏÂÃæÕâ¸ö¹ØÓÚÍøÒ³µÇ¼¹¦ÄܵÄÐèÇó£º

Feature: Login
In order to access my account
As a user of the website
I want to log into the website Scenario: Logging in with valid credentials
Given I am at the login page
When I fill in the following form
| field | value |
| Username | xtrumanx |
| Password | P@55w0Rd |
And I click the login button
Then I should be at the home page

Æä¿É¶ÁÐԷdz£Ç¿£¬Êǰɣ¿ÒÔÉϵÄÏêϸÐèÇóÊÇͨ¹ýGherkinÓïÑÔÀ´ÃèÊöµÄ¡£GherkinÊÇÒ»ÖÖÁìÓòÌØ¶¨ÓïÑÔ£¬ËüÔÊÐíÎÒÃÇÔÚ²»½âÊ;ßÌåÖ´ÐÐϸ½ÚµÄÇé¿öÏ£¬ÏêϸÃèÊöÓ¦ÓÃÓ¦¸ÃÈçºÎÖ´ÐС£ÒÔÉÏÏêϸÐèÇóµÄ´ó²¿·ÖÄÚÈÝÊÇÓÉ×ÔÓÉÎÄ×Ö×é³É£»Ö»Óм¸¸öÌØ¶¨µÄGherkin¹Ø¼ü×Ö£ºFeature¡¢Scenario¡¢Given¡¢When¡¢AndºÍThen£¬ÆäËûµÄ¶¼ÊÇ×ÔÓÉÎÄ×Ö£¬²¢ÇÒÖ÷Òª¼Ç¼Á˹¦ÄÜÌØÐÔÊÇÈçºÎ±»Ê¹Óõġ£

GherkinÊÇÒ»ÖÖ»ùÓÚÐеıà³ÌÓïÑÔ£¬³¡¾°ÖеÄÿһÐУ¨Line£©¾ÍÊÇÒ»¸ö²½Ö裨Step£©¡£¡°Logging in with valid credentials¡±³¡¾°ÖеĵÚÒ»¸ö²½ÖèÊÇ¡°Given I am at the login page¡±¡£¸Ã²½ÖèÐèÒªÒ»¸ö¾ßÌå²½Ö趨Ò壬ÕâÑùÎÒÃǵIJâÊÔÖ´ÐÐÕߣ¨test runner£©²ÅÄÜÖªµÀÈçºÎÈ¥Íê³É¸Ã²½Öè¡£Spec FlowÖеIJ½Ö趨ÒåÆäʵ¾ÍÊÇÒ»¸ö´øÓбäÁ¿µÄ·½·¨,¶ø¸Ã±äÁ¿°üº¬Óиò½ÖèµÄ¾ßÌåÎı¾¡£ËùÓв½Ö趨Òå·½·¨¶¼Ðè°üº¬ÓÚÒ»¸öº¬ÓÐBindingÊôÐÔµÄÀàÖС£

[Binding]
class LoginStepDefinitions
{
[Given("I am at the login page")]
public void GivenIAmAtTheLoginPage()
{
// TODO
}
}

ÉÏÃæµÄÀàºÍ·½·¨Ãû¶¼ÊÇËæÒâµÄ¡£ÕæÕýÖØÒªµÄÊÇÓ¦Óõ½ÀàºÍ·½·¨ÖеıäÁ¿¡£Èç¹ûûÓÐËüÃÇ£¬Spec Flow¾ÍÎÞ·¨È·Èϲ½Ö趨Òå·½·¨ºÍ¾ßÌå²½ÖèµÄ°ó¶¨¹ØÏµ¡£

ÏÖÔÚ¾Íʣϲ½Ö趨ÒåÖ´ÐÐÁË¡£¶øÕâʱºò¾Í¸ÃWatiNºÍNunitÉϳ¡ÁË¡£

WatiNÊÇÒ»¸ö»ùÓÚä¯ÀÀÆ÷µÄ×Ô¶¯»¯¹¤¾ß¡£ÎÒÃǽ«ÀûÓÃËüÀ´´ò¿ªÒ»¸öIEʵÀý£¬ä¯ÀÀURL£¬Ìî³ä±í¸ñ£¬µã»÷°´Å¥»òÁ´½ÓµÈ¡£Óë´Ëͬʱ£¬ÎÒÃǽ«ÀûÓÃNUnitÀ´¶ÏÑÔÎÒÃÇµÄÆÚÍû¡£¾¡¹ÜÈç´Ë£¬WatiNºÍNUnit²¢·ÇÊDZØÐèµÄ¡£Ò²¿ÉÒÔʹÓÃSelenium½øÐÐä¯ÀÀÆ÷×Ô¶¯»¯£»¶øÊÂʵÉÏ£¬Èκε¥Ôª²âÊÔ¿ò¼Ü¶¼¿ÉÓÃÀ´¶ÏÑÔ£¬ÉõÖÁ¿ÉÒÔʹÓÃWindows×Ô´øµÄÓ¦ÓÃ×Ô¶¯»¯¿â£¬±ÈÈ磺White£¬È»ºóΪÏàÓ¦µÄWindows Forms»òWPFÓ¦Óñàд×Ô¶¯»¯ÑéÊÕ²âÊÔ¡£

ÏÖÔÚÎÒÃǾÍÀ´³¢ÊÔΪһ¸öÕæÊµÓ¦Óô´½¨Êµ¼ÊµÄÑéÊÕ²âÊÔ¡£Õë¶Ô±¾ÎÄ£¬ÎÒÃǽ«Ê¹ÓøÃʵÀý³ÌÐò¡£¶ÁÕß¿ÉÒÔ´ÓÕâÀïµÄrepository»ñȡһ·Ý¡£¸Ãrepository»¹°üº¬ÍêÕûµÄÑéÊÕ²âÊÔ¹¤³Ì£¬µ«ÊÇÎÒ»¹Êǽ¨Òéͨ¹ýÖ´Ðб¾ÎÄʣϵÄÄÚÈÝÀ´´´½¨×Ô¼ºµÄÑéÊÕ²âÊÔ´úÂë¡£

ÏȾöÌõ¼þ

Spec FlowΪËùÓÐÖ§³ÖµÄµÚÈý·½²âÊÔÔËÐÐÆ÷ÊÚȨÒÔÔËÐÐÕæÕý·±ÖصÄÑéÊÕ²âÊÔ¡£ÕýÈçÇ°ÃæËùÌáµÄ£¬ÎÒÃǽ«Ê¹ÓÃNUnitÖ´ÐвâÊÔºÍWatiN×Ô¶¯»¯ä¯ÀÀÆ÷¡£ÒÔϾÍÊÇÈçºÎʹÓÃWatiN×Ô¶¯»¯ä¯ÀÀÆ÷ΪWatiNÖ´Ðйȸè²éѯµÄÀý×Ó(À´×ÔWaitNÍøÕ¾)¡£

[Test]
public void SearchForWatiNOnGoogle()
{
using (var browser = new IE("http://www.google.com"))
{
browser.TextField(Find.ByName("q")).TypeText("WatiN");
browser.Button(Find.ByName("btnG")).Click();

Assert.IsTrue(browser.ContainsText("WatiN"));
}
}

ÉÏÃæµÄ²âÊÔ´´½¨ÁËÒ»¸öÐÂIEʵÀý£¬È»ºó½«GoogleµÄURL´«¸ø¹¹ÔìÆ÷£¬È»ºóÓɹ¹ÔìÆ÷ÈÃä¯ÀÀÆ÷Ìø×ªµ½GoogleÒ³Ãæ¡£ËæºóѰÕÒÃüÃûΪ¡°q¡±µÄÎı¾¿ò¡£¸ÃÎı¾¿ò¾ÍÊÇÄãÒªÊäÈë¾ßÌå²éѯÄÚÈݵĵط½¡£ÕÒµ½¸ÃÎı¾¿òºó£¬ÊäÈë¡°WatiN¡±¡£½ô½Ó×Å£¬²éÕÒÃüÃûΪ¡°btnG¡±µÄ°´Å¥£¬È»ºóµã»÷Ëü¡£×îºó£¬ÓÉÒ»¸ö¶ÏÑÔÀ´È·¶¨Ò³ÃæÉÏ´æÔÚÓС°WatiN¡±£¨¿ÉÒÔÊÇÒ³ÃæÉÏÈκεط½£©¡£

ÒÔÉϵĴúÂëΪÎÒÃÇ¿ìËÙչʾÁËͨ¹ýWatiN×Ô¶¯»¯³£¹æÈÎÎñÊǶàôµÄ¼òµ¥£¬ÕâЩÈÎÎñ¿ÉÒÔÊÇÔÚä¯ÀÀÆ÷ÉÏÖ´ÐÐÀýÈçÌîдÎı¾¿ò¡¢µã»÷°´Å¥µÈ¶¯×÷¡£

½ÓÏÂÀ´£¬¾Í¿ÉÒÔÔÚVisual StudioÖÐΪÄãµÄÑéÊÕ²âÊÔ´´½¨ÐµÄÀà¿â¹¤³Ì¡£µ±ÄãÏÂÔØÍêNUnitºÍWatiNºó£¬Ä㽫ÐèÒªÌí¼Ó±ØÐèµÄDLLµ½ÄãµÄÑéÊÕ²âÊÔ¹¤³ÌÖС£´ÓÄãµÄNUnitÏÂÔØÖÐÌí¼ÓÒ»¸önunit.framework.dllÒýÓõ½ÄãµÄÑéÊÕ²âÊÔ¹¤³Ì¡£¶ÔÓÚWatiN£¬ÄãÔòÐèÒªÌí¼ÓÁ½¸öDLLÒýÓõ½ÄãµÄÑéÊÕ²âÊÔ¹¤³Ì£ºInterop.SHDocVw.dllºÍWatiN.Core.dll¡£

ÖµµÃÒ»ÌáµÄÊÇ£¬Äã¿ÉÒÔͨ¹ýNuGet»ñÈ¡NUnitºÍWatiNÕâÁ½¸öÏîÄ¿¡£ÕâÁ½¸ö¶¼ºÜÈÝÒ×ÔÚNuGetÖÐÕÒµ½£¬²¢ÄÜ×Ô¶¯Ìí¼Óµ½ÄãµÄ¹¤³ÌÖС£Èç¹ûÄãÒѾ­ÔÚÄãµÄÏîÄ¿ÖÐʹÓÃNuGeÁË£¬´ó¿ÉÒÔͨ¹ýËüÏÂÔØÕâÁ½¸öÏîÄ¿¡£

´ÓÍøÕ¾ÉÏ»ñȡһ·ÝSpec Flow£¬È»ºó°²×°µ½ÄãµÄϵͳÖС£¸úNUnitºÍWatiN²»Í¬£¬ÄãÐèÒªÔÚϵͳÖа²×°Spec Flow£¬¶ø²»ÊǼòµ¥µÄ¿½±´DllÎļþ¡£Spec Flow×Ô´øÓÐijЩ¹¤¾ß£¬Ã¿´ÎÍùÏîÄ¿ÖÐÌí¼ÓÒ»¸öÌØÐÔÎļþ£¬Ëü¶¼»á´´½¨ÏàÓ¦µÄÒþ²Ø´úÂëÎļþ¡£ÁíÍ⣬ÔÚÄã±à¼­ÌØÐÔÎļþʱ£¬Ëü»¹´øÓÐһЩÓï·¨¸ßÁÁºÍÆäËûµ÷Õû¡£

³É¹¦°²×°Spec Flowºó£¬¼ì²é°²×°Ä¿Â¼£¨Ä¬ÈÏΪProgram Files£©¡£ÀïÃæÓÐÒ»¶ÑDLLÎļþ£¬µ«ÊÇÄãÖ»ÐèÒªÌí¼Ó¸ÃÒýÓõ½ÄãµÄ¹¤³ÌÖУºTechTalk.SpecFlow.dll¡£

½¨Á¢ÑéÊÕ²âÊÔ¹¤³Ì

ÔÚÎÒÃǽøÒ»²½±àдÑéÊÕ²âÊÔ֮ǰ£¬ÎÒÃÇÐèÒª½¨Á¢ÎÒÃǵÄÑéÊÕ²âÊÔ¹¤³Ì¡£ÎÒÃǽ«ÔÚ¹¤³ÌÖÐÌí¼Ó¼¸¸öÎļþ¼ÐÒÔ±ãʹÏîÄ¿¸üÓÐÌõÀí¡£

Features

ËùÓеÄ˵Ã÷¶¼·ÅÔÚÕâ¸öÎļþ¼ÐÏ¡£

StepDefinitions

ËùÓÐÇé¾°²½ÖèµÄ²½Ö趨Ò彫·ÅÔÚÕâ¸öÎļþ¼ÐÏÂ

StepHelpers

´´½¨Spec FlowÌØÐÔÎļþ

ÔÚFeaturesÎļþ¼ÐÖÐÌí¼ÓÒ»¸öеÄÃû×ÖΪLogin.featureµÄSpec FlowÌØÐÔÎļþ¡£¸ÃÎļþ´øÓÐÕë¶Ô³¡¾°ÖÐÐÂÔöÌØÐԵĹæ¸ñ˵Ã÷¡£¿ÉÒÔ½«Æäɾ³ý£¬È»ºóÌí¼ÓÒÔÏÂÎı¾¡£

Feature: Login

FeatureÔÚGherkinÖÐÊǹؼü×Ö¡£ËüÐèÒªÔÚÿ¸öfeatureÎļþÖгöÏÖÒ»´Î£¬½ô½Ó×ÅËüÊÇÒ»¸öðºÅºÍÆäÌØÐÔÃû¡£È»ºóÄã¿ÉÒÔͨ¹ýÈÎÒâÐеÄ×ÔÓÉÎÄ×ÖÀ´ÃèÊö¸ÃÌØÐÔ¡£ÎªÁ˱£³Ö¼òÒ×ÐÔ£¬GherkinµÄ´´½¨Õß½¨ÒéÓû§¾¡Á¿½«Îĵµ±£³Ö×î¶Ì£¬²¢×ñÑ­ÒÔϸñʽ£º

In order to realize a named business value
As an explicit system actor
I want to gain some beneficial outcome which furthers the goal

¸öÈË¿´À´£¬ÎÒ¸üÇãÏòÓÚÌø¹ýÉÏÊöÃèÊö£¬ÏñµÇ¼ÕâÑùÄÜ×ÔÎÒÃèÊöµÄÌØÐÔ£¬Èç¹ûÄã³¢ÊÔÒÀ¾ÝÄ³Ò»ÌØ¶¨¸ñʽ½«ÆäÃèÊöµÄ»°£¬·´¶øÈÃÈËÀ§»ó£»ÓеÄʱºòºÜÄÑÇø·Ö³öµÚÒ»ÐÐÖеġ°named business value¡±ºÍµÚÈýÐÐÖÐÄãÓ¦ÃèÊöµÄ¡°beneficial outcome¡±Ö®¼äµÄ²»Í¬¡£ÐèÒª¼ÇסµÄÊǸò¿·ÖÊÇ×ÔÓÉÎÄ×Ö£¬Äã¿ÉÒÔÈÎÒâÃèÊö¡£½ÓÏÂÀ´¾ÍÈÃÎÒÃÇÏÈÌø¹ýÕâÒ»¶Î£¬¿ªÊ¼±àдÇé¾°¡£

Feature: Login
Scenario: Logging in with valid credentials

¸úFeatureÒ»Ñù£¬ScenarioÒ²ÊÇGherkinµÄÒ»¸ö¹Ø¼ü×Ö£¬ÆäºóÃæ½ô½Ó×ÅÒ»¸öðºÅºÍÆäÃüÃû¡£¸úFeature²»Í¬µÄÊÇ£¬scenario²»ÄÜÔÚÒ»ÐÐÖоÍÍê³É£¬ËüÐèÒªÓɸ÷¸ö²½ÖèÒ»ÆðÀ´Íê³Éscenario¡£ÎÒÃÇ¿ÉÒÔÏëÒ»Ï룺ÎÒÃÇÐèÒª×öʲôͨ¹ýÓÐЧƾ֤À´³É¹¦µÇ¼£¿

1.ÌîдµÇ¼±íµ¥

2.µã»÷µÇ¼°´Å¥

µ«ÊÇÇÒÂý£¬ÔÚÎÒÃÇÄܹ»ÌîдµÇ¼±íµ¥Ç°£¬ÎÒÃÇÐèÒª´ò¿ªÓÐ×ŵǼ±íµ¥µÄÒ³Ãæ¡£Ö®ºó£¬ÎÒÃÇÐèÒª¼ì²éÎÒÃÇÊÇ·ñ³É¹¦µÇ¼¡£¿ÉÒÔ¼ÙÉèÔڵǼºó£¬ÎÒÃǽ«±»Öض¨Ïòµ½Ö÷Ò³£¬´Ó¶øÒâζ×ÅÎÒÃÇÒѾ­³É¹¦µÇ¼¡£

ÏÖÔÚÎÒÃǵÄscenarioÓÐÁËǰÌáÌõ¼þ£¨±ÈÈ磺ÎÒÃDZØÐëÔÚµÇÂ¼Ò³Ãæ£©ºÍºóÖÃÌõ¼þ£¨±ÈÈ磺ÎÒÃÇÔÚÖ÷Ò³£©¡£GherkinÖУ¬Ç°ÌáÌõ¼þÐè´Ó¹Ø¼ü×ÖGiven¿ªÊ¼£¬¶øºóÖÃÌõ¼þÐèÒªÓɹؼü×ÖWhen¿ªÊ¼¡£

Feature: Login
Scenario: Logging in with valid credentials
Given I am at the 'Login' page
When I fill in the following form
| field | value |
| Username | testuser |
| Password | testpass |
And I click the 'Login' button
Then I should be at the 'Home' page

ÊÇ·ñ×¢Òâµ½ËüµÄÀà±í½á¹¹£¿Spec Flow»á×Ô¶¯½«µÚÒ»ÐÐбÌ廯£¬¸ÃÐÐÔڹܵÀÏÞÖÆÐÐÖУ¬²¢ÓɹܵÀ¿ªÊ¼¡£µÚÒ»ÐÐΪ±íÍ·£¬½ô½Óן÷ÐÐÖеÄÿÁн«Ö¸´ú±íÍ·Öж¨ÒåµÄÈÎÒâÎı¾¡£±ÈÈ磬Password¾ÍÊÇfieldÔÚµÚ¶þÐеÄÄÚÈÝ£¬¶øtestuserÔòÊÇvalueÁÐÔÚµÚÒ»ÐеÄÖµ¡£

ͬʱ£¬Ò²Ó¦×¢Òâµ½ÓÉAnd¿ªÊ¼µÄ²½Öè¡£And¹Ø¼ü×Ö¿ÉÒÔʹÓÃÓÚÈÎÒ»²½ÖèÖ®ºó£¬²¢½«±»×Ô¶¯ÈÏΪÓëǰһ²½ÖèÊôÓÚͬһÀàÐÍ¡£Èç¹ûAnd²½Öè½ô½Ó×ÅGiven²½Ö裬 ÄÇô¸Ã²½ÖèÒ²±»ÈÏΪÊÇÒ»¸öGiven²½Öè¡£ÔÚÉÏÊöÀý×ÓÖУ¬¸ÃAnd²½Öè±»ÈÏΪÊÇWhen²½Öè¡£When²½Öè²»ÓÃ×öpre»òpostÌõ¼þ£¬µ«ÊÇscenarioÐèÒªÕâÒ»²¿·ÖÓÃÓÚ½øÒ»²½Ö´ÐС£

´´½¨µÚÒ»¸ö²½Ö趨Òå

ÏÖÔÚÎÒÃÇÍê³ÉÁ˶ÔLoginÌØÐԵ͍Ò壬µ«ÊÇÎÒÃǵÄtest runner»¹²»ÖªµÀÈçºÎÖ´ÐиÃÌØÐÔÇé¾°ÖеÄÿһ¸ö²½Öè¡£ÎÒÃÇÐèҪΪLoginÌØÐÔÇé¾°ÖеÄ4¸ö²½ÖèÒ»Ò»¶¨Ò塣ΪÁËÍê³ÉÕâ¸ö£¬ÎÒÃǽ«ÔÚStepĿ¼Öд´½¨Ò»¸öÀ࣬²¢½«ÆäÃüÃûΪLoginSteps¡£ÎªÁËÈÃSpec FlowÖªµÀ¸ÃÀຬÓв½Ö趨Ò壬ÎÒÃǸø¸ÃÀà°ó¶¨ÏÂBindingÊôÐÔ¡£¸ÃBindingÊôÐÔÊôÓÚTechTalk.SpecFlowÃüÃû¿Õ¼äµÄÒ»²¿·Ö¡£

using TechTalk.SpecFlow;
[Binding]
class LoginSteps
{
}

½ÓÏÂÀ´£¬ÎÒÃÇÐèÒª¸øÃ¿¸ö²½Öè´´½¨Ò»¸ö·½·¨¡£¸Ã·½·¨½«¸æËßSpec FlowÈçºÎÖ´ÐÐÿһ²½Öè¡£ÏÖÔÚÎÒÃǾÍֻΪµÚÒ»¸ö²½Öè½øÐоßÌå²½Ö趨Ò壺¡°Given I am at the ¡®Login¡¯page¡±¡£

[Given("I am at the 'Login' page")
public void GivenIAmAtTheLoginPage()
{
// TODO
}

Çë×¢Òâµ½¸Ã·½·¨´øÓÐÒ»¸öÊôÐÔ¡£¸ÃÊôÐÔ½«¸æËßSpec Flow´Ë·½·¨ËùÖ¸´úµÄ²½Ö裬ÿ¸ö²½Öè¶¼ÓÐÏàÓ¦µÄÊôÐÔ¡£ÈκÎÒ»¸öfeatureÎļþÖеÄÈÎÒâÒ»¸öÒԹؼü×Ö¡°Given¡±¿ªÊ¼µÄ²½Ö裬½ô½Ó×ŵÄÎı¾ÊÇ¡°I am at the ¡®Login¡¯page¡±µÄ¶¼½«»áÓë¸Ã·½·¨Åä¶Ô¡£

ÏÖÔÚÎÒÃÇÐèҪΪ¸Ã²½Ö趨Òå±àд¾ßÌåÖ´ÐС£ÎÒÃÇÐèÒª¸æËßWatiNÆô¶¯ä¯ÀÀÆ÷£¬È»ºó·ÃÎʳÌÐòµÇÂ¼Ò³Ãæ¡£µ«ÊÇÔÚÕâ֮ǰÎÒÃÇÐèÒª´´½¨Ò»¸öä¯ÀÀÆ÷ʵÀý¡£ÎÒÃÇҲҪȷ±£scenarioÖÐÊ£ÓಽÖèÒ²½«Ê¹ÓøÃä¯ÀÀÆ÷ʵÀý¡£ÎªÁ˱£Ö¤scenarioÖÐËùÓв½ÖèʹÓõÄÊÇͬһ¸öä¯ÀÀÆ÷ʵÀý£¬ÎÒÃÇÐèҪΪä¯ÀÀÆ÷¶ÔÏó´´½¨Ò»¸öʵÀý£¬²¢½«Æä±£´æÓÚScenarioContext×ÖµäÖС£ScenarioContext×Öµä¿ÉÒÔÓÃÓÚ±£´æScenarioÖ´Ðйý³ÌÖеÄÊý¾Ý¡£ÎÒÃÇ»¹Òª´´½¨Ò»¸öÃûΪWebBrowserµÄhelperÀ࣬¸ÃÀཫ±£´æscenarioÖ´ÐÐʱµÄä¯ÀÀÆ÷ʵÀý¡£

using TechTalk.SpecFlow;
using WatiN.Core; static class WebBrowser
{
public static IE Current
{
get
{
if(!ScenarioContext.Current.ContainsKey("browser"))
ScenarioContext.Current["browser"] = new IE(); return ScenarioContext.Current["browser"] as IE;
}
}
}

ÒÔÉϵÄHelperÀຬÓÐCurrentÊôÐÔ£¬Ëü½«»ñÈ¡ÏÖÓÐä¯ÀÀÆ÷ÓÃÓÚĿǰÕýÔÚÖ´ÐеÄscenario¡£Èç¹ûËüûÔÚScenarioContext×ÖµäÖÐÕÒµ½ä¯ÀÀÆ÷ʵÀý£¬Ëü½«´´½¨Ò»¸öÐÂä¯ÀÀÆ÷ʵÀý£¬È»ºó½«ÆäÌí¼Óµ½×ÖµäÖС£ÕâÑù´æÔÚÓÚ×ÖµäÖеÄä¯ÀÀÆ÷ʵÀýÓÖ»ØÀ´ÁË¡£

×îºó£¬ÎÒÃÇÖÕÓÚ¿ÉÒÔ»ØÈ¥ÊµÏÖÎÒÃǵIJ½Ö趨ÒåÁË¡£ÔÚʾÀýÓ¦ÓÃÖУ¬µÇÂ¼Ò³Ãæ´æÔÚÓÚhttp://localhost:9876/authentication/login¡£ÎÒÃǽ«Í¨¹ýÈõ±Ç°Scenarioä¯ÀÀÆ÷ʵÀý¶¨Î»µ½¸ÃURLÒÔÖ´ÐÐÎÒÃǵIJ½Ö趨Òå¡£ÎÒÃÇ¿ÉÒÔͨ¹ýä¯ÀÀÆ÷ʵÀý»Øµ½Ö÷Ò³£¬È»ºóµã»÷µÇ¼Á´½ÓÀ´Ö´ÐÐÎÒÃǵIJ½Ö趨Ò壬¶øÕâÔÚÏÖÔÚ¿´À´ÊÇ×î¼òµ¥µÄ¡£È»ºó£¬ÎÒÃǽ«Öع¹ÎÒÃǵIJ½Ö趨Ò壬ÕâÑùÎÒÃÇÖ»ÒªÓÐÒ»¸ö²½Ö趨Òå¾ÍÄܽâ¾öÓ¦ÓÃÖÐËùÓÐÒ³ÃæÌø×ªÎÊÌâ¡£

[Given("I am at the 'Login' page")
public void GivenIAmAtTheLoginPage()
{
// Make sure to add the namespace the WebBrowser class is inside
WebBrowser.Current.GoTo("http://localhost:9876/authentication/login");
}

½áβ

ÏÖÔÚÎÒÃÇÒѾ­Îª³¢ÊÔÖ´ÐÐÑéÊÕ²âÊÔ×öºÃ×¼±¸ÁË¡£ËäÈ»ÎÒÃÇ»¹Ã»Íê³ÉËùÓеIJ½Ö趨Ò壬µ«ÊÇÎÒÃÇÏëÔÚ½øÒ»²½ÉîÈëǰ£¬È·±£¸÷·½Ãæ¶¼ÒѾ­ÕýÈ·ÏνÓÉÏ¡£ÔÚÖ´ÐвâÊÔ֮ǰ£¬ÎÒÃÇÒª±£Ö¤ËùÓмӵ½¹¤³ÌÖеÄÒýÓö¼ÒÑÉèÖóÉÁËCopy Local¡£Èç¹ûÊÇͨ¹ýNuGetÌí¼ÓµÄWatiN£¬Interop.SHDocVw DLLÔòĬÈϽ«ËüµÄEmbed InteropÊôÐÔÉèÖóÉTrue¡£Õâʱ£¬ÐèҪȷ±£½«Embed InteropÊôÐÔÉèÖóÉfalse£¬ÕâÑù²ÅÄܽ«ËüµÄCopy LocalÊôÐÔÉèÖóÉTrue¡£

ͬʱ£¬ÎÒÃÇÒ²ÐèÒªÔÚµ¥Ï̵߳ÄApartment StateÖÐÔËÐÐNUnit£¬²»È»¾Í²»ÄÜ×Ô¶¯»¯IEä¯ÀÀÆ÷¡£Ö®ËùÒÔÑ¡ÔñIE£¬¶ø·ÇFirefoxÊÇÒòΪFirefox³ÖÐø¸üÐÂËüµÄÖ÷Òª°æ±¾£¬¶øÕâ»á²»¶ÏÆÆ»µWatiNÓëFirefoxÖ®¼äµÄÏνӡ£

ÉèÖÃNUnitµÄApartment StateÐèҪʹÓõ½ÅäÖÃÎļþ¡£Íù¹¤³ÌÖÐÌí¼ÓÒ»¸öapp.configÎļþ£¬²¢Ìí¼ÓÒÔÏÂÅäÖá£

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="NUnit">
<section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
</sectionGroup>
</configSections>
<NUnit>
<TestRunner>
<!-- Valid values are STA,MTA. Others ignored. -->
<add key="ApartmentState" value="STA" />
</TestRunner>
</NUnit>
</configuration>

Ö´ÐÐÑéÊÕ²âÊÔLogin.featureÎļþ½«ÓиöÃû×ÖΪLogin.feature.cs£¨»òÕß.vb£©µÄ´úÂëÒþ²ØÎļþ¡£¸ÃÎļþÊǺ¬ÓÐTestFixtureÊôÐÔµÄÀ࣬ÕâÑùNUnit²ÅÄÜÖªµÀÐèÒª²âÊÔÄĸöÀà¡£Èç¹ûÄãµÄVisual StudioÖÐÒѾ­°²×°ÁËNUnit²âÊÔÔËÐвå¼þ£¬±ÈÈ磺TestDriven.Net»òReSharper£¬ÄÇôÄã¾Í¿ÉÒÔʹÓÃLogin.feature.csÎļþÀ´ÔËÐвâÊÔ¡£Èç¹ûÄãûÓÐÏàÓ¦µÄ²âÊÔ²å¼þ£¬ÄÇôÄã¿ÉÒÔ´ò¿ªNUnit×Ô´øµÄ¡¢Î»ÓÚÓ¦ÓÃĿ¼ÏµIJâÊÔÔËÐÐÆ÷£¬È»ºó½«ÆäÖ¸ÏòÓÉÑéÊÕ²âÊÔ²úÉúµÄÅäÖÃÎļþÖУ¬ÕâÑùËü½«¶¨Î»Login.feature.csÖеIJâÊÔÉèÖá£

ÔÚÖ´ÐвâÊÔǰ£¬±£Ö¤Ó¦ÓõķþÎñÆ÷´¦ÓÚÔËÐÐ״̬¡£È»ºóÔËÐгÌÐò,Ò»¸öеÄIEʵÀý½«±»´ò¿ª£¬²¢Ìø×ªµ½µÇÂ½Ò³Ãæ¡£Èç¹û×öµ½ÁËÕâЩ£¬ÄǾÍ˵Ã÷¸÷¸ö²¿·ÖÒѾ­±»ÕýÈ·ÅäÖã¬ÎÒÃǾͿÉÒÔ¼ÌÐøÍê³ÉÊ£ÓàµÄ²½Ö趨Òå¡£Èç¹ûIEûÓдò¿ª£¬»òûÓÐÌø×ªµ½µÇÂ½Ò³Ãæ£¬ÄǾÍÒª½øÒ»²½µ÷ÊÔÁË¡£

Íê³ÉÊ£ÓàµÄ²½Ö趨Òå±àдʣÓಽÖ趨Ò彫»á·Ç³£¼òµ¥¡£ÄãÖ»Ðè¶ÔWatiN APIÓÐÒ»¶¨Á˽⣬ÕâÑù¾Í¿ÉÒÔÅäÖÃWatiNÒÔÌîд±íµ¥»ò²éÕÒ°´Å¥ºÍÁ´½Ó£¬È»ºó¶ÔÆäµã»÷¡£

Ê×ÏÈ£¬ÎÒÃdz¢ÊÔÇé¾°Öеĵڶþ¸ö²½Ö裺¡°When I fill in the following Form¡±¡£ÐèÒªÔÚLoginStepsÀàÖд´½¨Ò»¸ö·½·¨£¬²¢´øÓÐÒ»¸ö±äÁ¿½«Æä°ó¶¨µ½ÎÒÃÇĿǰÕýÔÚ¹¤×÷µÄ²½ÖèÉÏ¡£

[When("I fill in the following form")]
public void WhenIFillInTheFollowingForm(TechTalk.SpecFlow.Table table)
{
// TODO
}

×¢Òâ´«µ½¸Ã²½Ö趨ÒåÖеIJÎÊý¡£¸ÃTable¶ÔÏó°üº¬ÓÐÎÒÃÇÔÚÇé¾°ÖÐËùÃèÊöµÄÖµ¡£¶øWatiNÔÚÆäÃüÃû¿Õ¼äÖÐÒ²ÓÐÒ»¸öTableÀ࣬ΪÁ˱ÜÃâ³åÍ»£¬ÎÒ¶Ô¸ÃTable¶ÔÏó²ÉÓÃÁËÍêÈ«ÏÞ¶¨Ãû¡£¸ÃTable¶ÔÏó½«ÓÉÐÐ×é³É¡£ÐÐÖеÄÿÁпÉÒÔͨ¹ýË÷Òý»òÁÐÃûÀ´»ñÈ¡¡£ÁÐÃûÓÉÇé¾°ÖбíµÄµÚÒ»ÐÐÀ´¶¨Òå¡£

[When("I fill in the following form")]
public void WhenIFillInTheFollowingForm(TechTalk.SpecFlow.Table table)
{
foreach(var row in table.Rows)
{
var textField = WebBrowser.Current.TextField(Find.ByName(row["field"])); if(!textField.Exists)
Assert.Fail("Expected to find a text field with the name of '{0}'.", row["field"]);
textField.TypeText(row["value"]);
}
}

Êǵģ¬Ö»ÐèÒª5ÐУ¬ÎÒÃǾÍÍê³ÉÁËÌîд±íµ¥µÄ²½Ö趨Òå¡£ÎÒÃÇÊ×ÏÈÑ­»·±íÖеÄÐУ¬È»ºóÊÔͼ²éÕÒÏàÓ¦µÄ´øÓÐÃüÃûÊôÐÔµÄfieldÎı¾£¬ÓÃÀ´Æ¥Å䵱ǰÐÐÖÐfieldÁÐÖµ¡£Èç¹ûûÓÐÆ¥Åäµ½ÏàÓ¦µÄÎı¾field£¬²âÊÔ½«»áʧ°Ü£¨µ«ÊÇ»áÓÐÏàÓ¦ÐÅÏ¢±»¼Ç¼ÏÂÀ´£©¡£µ«ÊÇÈç¹ûÎÒÃÇÕÒµ½Ò»¸öÆ¥ÅäµÄÎı¾field£¬WatiN½«»á±»Ö¸Ê¾ÊäÈëÔÚµ±Ç°ÐÐËùÕÒµ½µÄÁÐÖµ¡£

½ÓÏÂÀ´Ê£ÓàµÄ²½Ö趨ÒåÒ²»ù±¾ÀàËÆ¡£ÒÔϾÍÊÇÎÒÃÇϸö²½ÖèµÄ´úÂ룺¡°And I click the ¡®Login¡¯button¡±¡£

[When("I click the 'Login' button")]
public void AndIClickTheLoginButton()
{
var loginButton = WebBrowser.Current.Button(Find.ByValue("Login")); if(!loginButton.Exists)
Assert.Fail("Expected to find a button with the value of 'Login'."); loginButton.Click();
}

¶ø×îºóÒ»²½£¬ÎÒÃÇÔòÐèҪŪÇåÈçºÎÈ¥ÑéÖ¤ÎÒÃÇÊÇ·ñÔÚÖ÷Ò³ÉÏ¡£ÎÒÃÇ¿ÉÒÔ¼ì²âÆäÎļþ±êÌâÀ´¿´ËüÊÇ·ñÂú×ãÎÒÃǵÄÐèÒª£»»òÕß¼ì²âURLÀ´²é¿´ÆäÊÇ·ñÓëÆÚÍûµÄÖ÷Ò³URLÆ¥Åä¡£ÕâÀïÎÒÃǽ«Í¨¹ýURLÀ´¼ì²â¡£µ«ÐèÒª¼ÇסµÄÊDz½Ö趨ÒåµÄÖ´ÐлáÍêÈ«ÒÀÀµÓÚ¾ßÌåÓ¦ÓãºÈç¹ûÎÒÃÇ´óÁ¿Ê¹ÓÃAjax½øÐÐÒ³ÃæÇл»£¬URL¿ÉÄܲ»»á±»¸üУ¬´Ó¶ø¿ÉÄÜÎÞ·¨ÑéÖ¤ÎÒÃÇÊÇ·ñÔÚÕýÈ·Ò³ÃæÉÏ¡£

[Then("I should be at the 'Home' page")]
public void ThenIShouldBeAtTheHomePage()
{
var expectedURL = "http://localhost:9876/";
var actualURL = WebBrowser.Current.Url;
Assert.AreEqual(expectedURL, actualURL);
}

ÏÖÔÚÖØÐÂÖ´ÐÐÑéÊÕ²âÊÔ£¬¶øÕâ´ÎËü½«Ö´ÐÐËùÓв½Öè¡£Èç¹û³É¹¦ÁË£¬ÄÇô¹§Ï²Ä㣬Äã³É¹¦µØÍ¨¹ýSpec Flow±àдÁ˵ÚÒ»¸öÑéÊÕ²âÊÔ¡£

ÖØ¹¹²âÊÔ´úÂëÏÖÔÚÎÒÃǵIJ½Ö趨ÒåÒѾ­³É¹¦ÔËÐÐÁË£¬¿ÉÊÇÎÒÃÇ»¹ÊÇÐèҪͣÏÂÀ´»Ø¹Ëһϡ£ÎÒÃÇÒѾ­ÓÐÁËÕë¶ÔµÇ¼°´Å¥µÄ²½Ö趨Ò壬Óкܴó¿ÉÄÜÎÒÃǵÄÓ¦ÓÃÖн«ÓдóÁ¿µÄ°´Å¥¡£ÎÒÃÇÊÇ·ñΪÑéÊÕ²âÊÔ¼¯ÖеÄÿ¸ö°´Å¥Ìṩһ¸ö²½Ö趨ÒåÄØ£¿ÕâЩ²½Ö趨ÒåÖÐΨһһ¸öÐèÒªÐ޸ĵĵط½¾ÍÊÇWatiNÔÚÄ³Ò³ÃæÉÏѰÕÒÆÚÍû°´Å¥Ëù¶ÔÓ¦µÄ¾ßÌåÎı¾£¬ÒÔϾÍÊǸöÀý×Ó£º

[When("I click the 'Login' button")]
public void AndIClickTheLoginButton()
{
var loginButton = WebBrowser.Current.Button(Find.ByValue("Login")); if(!loginButton.Exists)
Assert.Fail("Expected to find a button with the value of 'Login'.");
loginButton.Click();
}
[When("I click the 'Register' button")]
public void AndIClickTheRegisterButton()
{
var registerButton = WebBrowser.Current.Button(Find.ByValue("Register"));
if(!registerButton.Exists)
Assert.Fail("Expected to find a button with the value of 'Register'.");
registerButton.Click();
}

ÐÒÔ˵ÄÊÇ£¬Spec FlowΪ¸ÃÎÊÌâÌṩÁ˽â¾ö·½°¸¡£Äã¿ÉÒÔʹÓÃÕýÔò±í´ïʽ£¬¸Ã±í´ïʽ±ØÐëÊÇ´«µÝ¸ø°ó¶¨ÊôÐÔµÄ×Ö·û´®£¬ÕâÑùÎÒÃǾͽ«²»Í¬²½Öè°ó¶¨µ½Í¬Ò»¸ö²½Ö趨Òå¡£ÈκÎÓɸÃÕýÔò±í´ïʽ²¶»ñµÄÎı¾¶¼¿ÉÒÔµ±×÷Ò»¸ö²ÎÊý´«µÝ¸ø²½Ö趨Òå¡£¾ßÌåÀý×ÓÈçÏ£º

[When("I click the '(.*)' button")]
public void AndIClickAButton(string buttonText)
{
var button = WebBrowser.Current.Button(Find.ByValue(buttonText)); if(!button.Exists)
Assert.Fail("Expected to find a button with the value of '{0}'.", buttonText);
button.Click();
}

¸Ã²½Ö趨Òå¿ÉÒÔÊÇÒÔÏÂÈÎÒâÒ»ÖÖ£º

µã»÷¡®µÇ½¡¯°´Å¥

µã»÷¡®×¢²á¡¯°´Å¥

µã»÷¡®ÈÎÒâÎı¾¡¯°´Å¥

Äã¿ÉÒÔʹÓøü¼ÇÉÀ´ÈÃËùÓв½Ö趨Òå¿ÉÖØÓá£ÈÃËùÓеIJ½Ö趨Òå¶¼¾ßÓпÉÖØÓÃÐÔÊǸö·Ç³£ºÃµÄÏë·¨£¬ÎÒÃÇÓ¦¸Ã±ÜÃâ±àдֻÓÐÄ³Ò»ÌØ¶¨Çé¾°²Å¿ÉÒÔÓõIJ½Ö趨Òå¡£¿ÉÖØÓÃÐÔÔÊÐíÄãд³öµÄScenarioÄÜÁ¢¼´Ê¹Óã¬ÒòΪÄãÒѾ­ÓµÓÐÒ»¸ö¿ÉÒÔÖØ¸´Ê¹ÓõIJ½Ö趨Òå¡£µ«ÊÇҲû±ØÒªÔÚÐèҪǰ¾Í°Ñ²½Ö趨Òå±àд³öÀ´£¬ÔÚÐèҪʱ±àд¾ÍºÃÁË¡£´ó¶àÊýÇé¿öÏ£¬ÄãµÄ²âÊÔËùÐèÒª×öµÄ»ù±¾ÉÏÊÇͬÑùµÄÊÂÇé£ºÌø×ªµ½Ò»¸öÒ³Ãæ£¬Ìîд±íµ¥£¬µã»÷Ö®ÀàµÄ¡£Ö»ÓÐÔÚ¼«ÉÙÊýÇé¿öÏ£¬Äã²ÅÐèҪΪһ¸öÇé¾°±àÐ´ÌØÊâ²½Ö趨Ò壬±ÈÈçÑéÖ¤jQuery UIÈÕÀúÊÇ·ñÔÚµã»÷Ò»¸öÐèÒªÈÕÆÚÖµµÄÎı¾¿òʱµ¯³ö£¬ÕâÑù²»Ñ°³£µÄÀý×Óʱºò²ÅÐèÒª¡£

¶ÔÓÚ¾ßÌåÈçºÎÖØ¹¹ÄãµÄ²½Ö趨Ò壬ÎÒ½«Æä×÷ΪÁ·Ï°Áô¸øÄ㣬ȷ±£Ã¿¸ö¶¼¾ßÓпÉÖØÓÃÐÔ¡£Ö®ºó£¬Äã¾Í¿ÉÒÔ±àдеÄÌØÐÔÎļþ£¬¶øÒòΪËùÐèµÄ²½Ö趨Òå¶¼ÒѾ­×¼±¸ºÃÁË£¬ËüÃǶ¼¿ÉÒÔÁ¢¿Ì¹¤×÷¡£µ±È»£¬Ä㽫ÐèÒª¸ü¶àµÄ²½Ö趨ÒåÀ´×Ô¶¯»¯²»Í¬ÐÐΪ£¨±ÈÈ磺µã»÷Ò»¸öÁ´½Ó£©£¬ÄãÒ²ÐèÒª½øÒ»²½¸ÄÉÆµ±Ç°²½Ö趨Ò壬ÒÔ±ãÔÚ²»Í¬Çé¾°ÖÐÒ²ÄÜʹÓá£Ä㽫עÒâµ½ÎÒÃÇµÄ±íµ¥Ìî³ä²½Ö趨ÒåÖд¦ÀíµÄ±íµ¥Ö»´øÓÐÎı¾¿ò¡£Èç¹ûÄãÏë¹´Ñ¡¸´Ñ¡¿ò£¬Í¨¹ývalue»òIDѰÕÒ°´Å¥£¬»òÆäËüÓë±íµ¥Ïà¹Ø²Ù×÷£¬ÄÇÄã¾ÍÐèÒªÔÚ±íµ¥Ìî³ä²½Ö趨ÒåÖÐÌí¼ÓÏàÓ¦µÄÂß¼­¡£×ܽá×ÜÖ®£¬ÒÔÉϾÍÊÇʹÓÃSpec Flow±àдÑéÊÕ²âÊÔÖ®Â᣾¡¹ÜÈç´Ë£¬Spec FlowÒÀÈ»Óиü¶àÌØÐÔÐèÒªÄã×Ô¼ºÈ¥·¢ÏÖ¡£±ÈÈ磺Spec Flow»¹Óиö¸ú×Ù»úÖÆ£¬Òò´ËÄãÄܸú×Ùij¸öÖ¸¶¨ÌØÐÔÔÚÌØ¶¨ÌØÐÔ£¬Çé¾°»ò²½ÖèǰºóÊÇÈçºÎÖ´ÐÐijЩ´úÂë¡£¶ÔÓÚÒÔÏÂÇé¿ö£¬Ëü¾Í»áÆðµ½·Ç³£´óµÄ×÷Ó㬱ÈÈ磺Èç¹ûÄãÐèÒªÔÚÍê³Éº¬Óеǽ¹¦Äܵij¡¾°ºóµÄµÇ³ö£»²âÊÔǰ׼±¸Êý¾Ý¿â£¬»òÖ»ÊǼòµ¥µØÔÚÿ¸ö²âÊÔ½áÊøºó¹Ø±Õä¯ÀÀÆ÷´°¿Ú¡£

Ëæ×ŲâÊÔ²»¶Ï±»´´½¨£¬Äã»á·¢ÏÖÍê³ÉÑéÊÕ²âÊÔ¼¯ËùÐèµÄʱ¼äÒ²»áËæÖ®Ôö¼Ó¡£µ«ÊÇÄãµÄ²âÊÔÖ´ÐеÃÔ½¿ì£¬Äã¾ÍÄÜÔ½¿ìµÃµ½»ØÀ¡£¬²¢ÕÒµ½ÎÊÌâËùÔÚ¡£ÄãÐèÒª¾¡¿ÉÄÜ¿ìµØÖ´ÐÐÄãµÄ²âÊÔ¡£·½·¨Ö®Ò»¾ÍÊǽ«ÄãµÄ²âÊÔ²¢Ðл¯£¬¶ø·Ç°´Ë³ÐòÖ´ÐУ¬ËùÓвâÊÔ½«Ò»ÆðÖ´ÐУ¬¶øÇÒ½«¸ü¿ì½áÊø¡£µ«ÊÇSpec Flow²¢Ã»ÓÐÌṩ²¢Ðд¦Àí¹¦ÄÜ£¬Òò´ËÐèÒª´Ó±ð´¦Ïë°ì·¨¡£Èç¹ûÄãʹÓÃNUnit£¬Äã¿ÉÒԲ鿴PNUnit¿´ÆäÊÇ·ñÂú×ãÄãµÄ²¢ÐÐÐèÇó¡£

Gherkin£¬ÎÒÃÇÔø¾­ÊÇʹÓÃDSLÀ´±àдÎÒÃǵÄÏêϸÐèÇó£¬Ëü±»Éè¼Æ×÷ΪÏνӼ¼ÊõÈËÔ±Óë·Ç¼¼ÊõÀûÒæÏà¹ØÕßÖ®¼äµÄÇÅÁº£¬ÒÔ±ãËûÃÇÔÚÄ³Ò»ÌØ¶¨ÌØÐÔÓ¦¸ÃÈçºÎÔËÐÐÉÏÄܹ»´ï³ÉÒ»Ö¡£ÓеÄÍŶÓÉõÖÁÓзǼ¼ÊõÀûÒæÏà¹ØÕß²ÎÓ뵽ʹÓÃGiven-When-ThenÓï¾äÀ´±àдʵ¼ÊÏêϸÐèÇ󡣿ÉÒÔÏëÏóµ½£¬Åàѵ´ó¼ÒÈçºÎ×öµ½Õâµã²¢²»Ì«ÄÑ£¬µ«ÊÇÆä½á¹ûÈ´´ó´ó²»Í¬¡£

Ò²ÓÐÒ»²¿·ÖÈ˸ü½øÒ»²½µØÊ¹ÓÃSpec Flow¡£ËûÃÇÔÚ¿ªÊ¼ËùÓÐÐÂÌØÐÔ¿ª·¢Ê±£¬Ê×ÏȾÍÊDZàдÏêϸÐèÇ󣬽Ó×ŵ¥Ôª²âÊÔ£¬×îºó²ÅÊÇÕæÕýµÄ±àÂ롣ȻºóËûÃÇͨ¹ý³£¹æµÄTDD red-green-refactorÑ­»·Í¨¹ýµ¥Ôª²âÊÔ£¬×îºóͨ¹ýÑéÊÕ²âÊÔ¡£Èç¹ûÄãÒѾ­ÔÚʵ¼ùTDD£¬´òËãΪÏîÄ¿±àдÑéÊÕ²âÊÔ£¬ÄÇÄãÓ¦¸Ã³¢ÊÔÏÂÑéÊÕ²âÊÔÇý¶¯¿ª·¢¡£

ÎÞÂÛÄãÊÇͨ¹ýʲô;¾¶£¬Äã¶¼ÐèÈ·±£Ëü¶ÔÄã¡¢»¹ÓÐÄãµÄ¹¤³Ì¶¼ÒªÐÐÖ®ÓÐЧ¡£Èç¹ûÄ㻹´¦ÓÚ½¨Ä£×´Ì¬£¬²¢²»¶ÏÐÞ¸ÄÄãµÄÓ¦Ó㬳ÖÐø¸üÐÂÑéÊÕ²âÊÔ¿ÉÄÜ»áÔì³ÉÒ»¶¨Ê±¼äÍÏÑÓ¡£Ê²Ã´Ê±ºòÓ¦¸Ã×ÅÊÖ±àдÑéÊÕ²âÊÔÊÇÄãµÄ¾ö¶¨£¬Ö»ÓÐÄãÄܱ£Ö¤Ëü½«·¢Éú¡£

   
4108 ´Îä¯ÀÀ       29
Ïà¹ØÎÄÕÂ

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

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

³ÖÐø¼¯³É²âÊÔ×î¼Ñʵ¼ù
×Ô¶¯»¯²âÊÔÌåϵ½¨ÉèÓë×î¼Ñʵ¼ù
²âÊԼܹ¹µÄ¹¹½¨ÓëÓ¦ÓÃʵ¼ù
DevOpsʱ´úµÄ²âÊÔ¼¼ÊõÓë×î¼Ñʵ¼ù
×îл¼Æ»®
DeepSeekÔÚÈí¼þ²âÊÔÓ¦ÓÃʵ¼ù 4-12[ÔÚÏß]
DeepSeek´óÄ£ÐÍÓ¦Óÿª·¢Êµ¼ù 4-19[ÔÚÏß]
UAF¼Ü¹¹ÌåϵÓëʵ¼ù 4-11[±±¾©]
AIÖÇÄÜ»¯Èí¼þ²âÊÔ·½·¨Óëʵ¼ù 5-23[ÉϺ£]
»ùÓÚ UML ºÍEA½øÐзÖÎöÉè¼Æ 4-26[±±¾©]
ÒµÎñ¼Ü¹¹Éè¼ÆÓ뽨ģ 4-18[±±¾©]

LoadRunnerÐÔÄܲâÊÔ»ù´¡
Èí¼þ²âÊÔ½á¹û·ÖÎöºÍÖÊÁ¿±¨¸æ
ÃæÏò¶ÔÏóÈí¼þ²âÊÔ¼¼ÊõÑо¿
Éè¼Æ²âÊÔÓÃÀýµÄËÄÌõÔ­Ôò
¹¦ÄܲâÊÔÖйÊÕÏÄ£Ð͵Ľ¨Á¢
ÐÔÄܲâÊÔ×ÛÊö

ÐÔÄܲâÊÔ·½·¨Óë¼¼Êõ
²âÊÔ¹ý³ÌÓëÍŶӹÜÀí
LoadRunner½øÐÐÐÔÄܲâÊÔ
WEBÓ¦ÓõÄÈí¼þ²âÊÔ
ÊÖ»úÈí¼þ²âÊÔ
°×ºÐ²âÊÔ·½·¨Óë¼¼Êõ

ij²©²ÊÐÐÒµ Êý¾Ý¿â×Ô¶¯»¯²âÊÔ
IT·þÎñÉÌ Web°²È«²âÊÔ
IT·þÎñÉÌ ×Ô¶¯»¯²âÊÔ¿ò¼Ü
º£º½¹É·Ý µ¥Ôª²âÊÔ¡¢Öع¹
²âÊÔÐèÇó·ÖÎöÓë²âÊÔÓÃÀý·ÖÎö
»¥ÁªÍøweb²âÊÔ·½·¨Óëʵ¼ù
»ùÓÚSeleniumµÄWeb×Ô¶¯»¯²âÊÔ