<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      【C#|.NET】從細節出發(三) 邏輯層事務和page object模式

      2014-07-17 12:29  熬夜的蟲子  閱讀(1975)  評論(0)    收藏  舉報

      一. 業務邏輯層的事務問題

      如果你的程序分層清晰并且系統禁用復雜存儲過程,那么在DA中的職責比較單一。程序的邏輯通過BLL調用各種不同模塊的DA來實現數據操作。如果當需要不同模塊在一個事務的時候,問題就產生了。

      如果你在bll引用System.Data...或者你在DA中穿插各種復雜邏輯的時候基本上你的工程已經不能算是好的程序了,

      1. 使用TransactionScope

      TransactionScope可以使代碼塊成為事務性代碼。但是需要開通MSDTC權限,并且TransactionScope的性能問題也一直存在爭議。

      2. 階段性提交

      這個涉及到框架層次的修改,會單獨開篇幅來說

      3. 使用委托 將多模塊提交匯聚在一起 和框架層次的階段性提交殊途同歸

      這個就是設計上的問題,將其他模塊的方法以委托方式傳入DA。舉個例子假如主線為消費記錄ConsumeRecord,分支線為消費詳細ConsumeRecordDetail和票據信息TravelTicket。其中TravelTicket完全為另一個服務模塊對自己為黑盒。ConsumeRecordDetail對自己為白盒。

        DA層

           public delegate BizResult<string> ArchiveTravelTicketDelegate( DbTransaction transaction, List<string> travelTicketIDList);
      

        主線服務BLL中,其中StartArchives為其他模塊但是需要包含近事務的方法

              private BizResult<string> InsertConsumeRecord(ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails)
              {
                  return consumeRecordArchiveTargetDA.DoArchive(consumeRecordEntity, consumeRecordDetails, new TravelTicketArchiveService().StartArchives);
              }

        主線服務DA中

           public BizResult<string> DoArchive(ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails, 
      ArchiveHelper.ArchiveTravelTicketDelegate archiveTravelTicket) { return ArchiveHandle(consumeRecordEntity, consumeRecordDetails, true, ConsumeRecordHandle, archiveTravelTicket); }
              public BizResult<string> ConsumeRecordHandle(DbTransaction currentTransaction, ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails)
              {
                  return ConsumeRecordHandle(currentTransaction, consumeRecordEntity, consumeRecordDetails,
                      (x, y) => InsertConsumeRecordLog(currentTransaction, consumeRecordEntity, true, false)
                      , InsertConsumeRecord, consumeRecordDetailArchiveDA.InsertConsumeRecordDetail);
              }
      

        其中InsertConsumeRecordLog,InsertConsumeRecord為主線自己的方法,ConsumeRecordDetail因為白盒可以直接使用consumeRecordDetailArchiveDA.InsertConsumeRecordDetail,archiveTravelTicket為黑盒。

         主線BaseDA中

           public BizResult<string> ArchiveHandle(ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails, bool isArchive,
      ConsumeRecordHandlerDelegate consumeRecordHandlerDelegate, ArchiveHelper.ArchiveTravelTicketDelegate archiveTravelTicket)
              {
                  using (DbConnection dbConnection = DbObject.CreateConnection())
                  {
                      dbConnection.Open();
      
                      BizResult<string> bizResult;
                      using (DbTransaction currentTransaction = dbConnection.BeginTransaction())
                      {
                          try
                          {
                              bizResult = consumeRecordHandlerDelegate(currentTransaction, consumeRecordEntity, consumeRecordDetails);
                              if (bizResult.IsSuccessful)
                              {
                                  if (archiveTravelTicket != null)
                                  {
                                      bizResult = archiveTravelTicket(currentTransaction,
                                                                      consumeRecordDetails.Select(x => x.TravelMoneyID).
                                                                          Distinct().ToList());
                                  }
                                  if (bizResult.IsSuccessful)
                                  {
                                      bizResult.Message = "xxx success";
                                      currentTransaction.Commit();
                                      return bizResult;
                                  }
                                  bizResult.Message = "xxx fail";
                              }
                              bizResult.Message = string.Format("{0}:{1}", isArchive, bizResult.Message);
                              currentTransaction.Rollback();
                          }
                          catch (Exception ex)
                          {
                              logger.Error(ex);
                              currentTransaction.Rollback();
                              throw;
                          }
                      }
                      return bizResult;
                  }
              }
      

      二. 測試環節的page object模式

        拿自動化測試Selenium為例,一般而言我們對于程序都是應付測試用例,針對測試用例寫出一個一個test-method。這樣無可厚非,使用page object模式可以讓代碼開起來更專業更精彩。

        在自動化測試中,主要關注UI的測試互動區域。 Page對象只是這些模型作為測試代碼中的對象可以減少了重復的代碼量,并且意味著,如果用戶界面的變化,也只需要修改一個地方。和軟件設計模式中dry(don't repeat yourself)類似。并且在page object模式中,PageObjects也可以實現頁于頁之間的邏輯。總得來說減少了代碼的重復,讓測試更具可讀性和強大的,提高了測試的可維護性,特別是當有頻繁變化的ui變更。

      舉個列子(java版本)

      public class LoginPageTest {
          private LoginPage loginPage;
          private final String username = "xx@163.com";
          private final String pwd= "Welcome1";
      
          @Before
          public void setUp() throws Exception {
              String applicationRoot = new File(
                      getClass().getProtectionDomain().getCodeSource().getLocation().getPath())
                      .getParent();
              System.setProperty("webdriver.chrome.driver", applicationRoot + "/chromedriver");
              WebDriver webDriver = new ChromeDriver();
              loginPage = new LoginPage(webDriver);
              loginPage.init();
          }
      
          @Test
          public void testLoginWithoutFakeCheckbox()
          {
              loginPage.setUserName(username);
              loginPage.setPassword(pwd);
              loginPage.pressLoginButton();
              assertThat(loginPage.getClassByLoginWithoutFakeCheckbox(), equalTo("checkbox-wrapper not-checked"));
          }
      
      
          @Test
          public void testLoginWithWrongUsername()
          {
              loginPage.setUserName("wrongusername");
              loginPage.setPassword(pwd);
              loginPage.pressCheckBox();
              loginPage.pressLoginButton();
              assertThat(loginPage.getClassByLoginWithWrongUserName(), equalTo("wrapper-input-text wrong"));
          }
      
          @Test
          public void testLoginWithNullPwd()
          {
              loginPage.clearInput();
              loginPage.setUserName(username);
              loginPage.pressCheckBox();
              loginPage.pressLoginButton();
              assertThat(loginPage.getClassByLoginWithNullPwd(), equalTo("wrapper-input-text wrong"));
          }
      
          @Test
          public void testLoginWithRightWay()
          {
              loginPage.clearInput();
              loginPage.setUserName(username);
              loginPage.setPassword(pwd);
              loginPage.pressCheckBox();
              loginPage.pressLoginButton();
              assertThat(loginPage.getTextByRightWay(), equalTo("選擇性別"));
          }
      
      }
      

        

      public class LoginPage {
          private final WebDriver webDriver;
          private final WebDriverWait wait;
          private JavascriptExecutor js;
          private final String username = "xx@163.com";
          private final String pwd = "Welcome1";
          private WebElement webElementLogin;
          private WebElement webElementPwd;
          private WebElement webElementInput;
      
          public LoginPage(WebDriver webDriver) {
              this.webDriver = webDriver;
              this.wait = new WebDriverWait(webDriver, 10);
              this.js = (JavascriptExecutor) webDriver;
          }
      
          public void init() {
              webDriver.get("http://root:root@localhost:8080/apitool/xxx/owF3PjkBFY5_56Q_KYs5fxmLZTKI");
              WebElement webElementName = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("p.text.bold.name")));
      
              if (webElementName != null) {
                  System.out.print(webElementName.getText());
              }
              webElementLogin = webDriver.findElement(By.cssSelector("input.input-text.login-input"));
              webElementLogin.sendKeys(username);
              webElementPwd = webDriver.findElement(By.cssSelector("input.input-text.password-input"));
              webElementPwd.sendKeys(pwd);
          }
      
          public String getClassByLoginWithoutFakeCheckbox() {
              WebElement webElementCss = wait.until(
                      ExpectedConditions.visibilityOfElementLocated(
                              By.xpath("http://*[contains(@class,'checkbox-wrapper not-checked')]")));
              WebElement webElementHref = webDriver.findElement(By.xpath("http://*[@id=\"login-page\"]/div/section/div/div[5]/div/div"));
              return webElementHref.getAttribute("class");
          }
      
          public String getClassByLoginWithWrongUserName() {
              webElementInput = webDriver.findElement(By.xpath("http://*[@id=\"login-page\"]/div/section/div/div[3]"));
              return webElementInput.getAttribute("class");
          }
      
          public String getClassByLoginWithNullPwd() {
              webElementInput = webDriver.findElement(By.xpath("http://*[@id=\"login-page\"]/div/section/div/div[3]"));
              return webElementInput.getAttribute("class");
          }
      
          public String getTextByRightWay() {
              GenderViewPage genderViewPage = new GenderViewPage(webDriver);
              return genderViewPage.getGenderText();
          }
      
          public void pressCheckBox() {
              js.executeScript("$('.fake-checkbox').attr('class','fake-checkbox active')");
          }
      
          public void clearInput() {
              webElementLogin.clear();
              webElementPwd.clear();
          }
      
          public void setUserName(String username) {
              webElementLogin.clear();
              webElementLogin.sendKeys(username);
      
          }
      
          public void setPassword(String password) {
              webElementPwd.clear();
              webElementPwd.sendKeys(pwd);
          }
      
          public void pressLoginButton() {
              js.executeScript("$('.login-button').trigger('touchstart')");
          }
      
          public void closeBrowser()
          {
              webDriver.quit();
          }
      }
      

      三. sql update 慎用位運算

      update t_User set valye = Flag | 4 where UserID = 1

      如果Flag字段中存在負數,在做位運算的時候,更新出非常大的數值,超過2的62次方

       

      希望對大家有幫助。

      主站蜘蛛池模板: 欧美人与性动交α欧美精品| 久久无码人妻精品一区二区三区| 91九色国产成人久久精品| 青青青青国产免费线在线观看| 日日碰狠狠添天天爽五月婷| 久久这里都是精品一区| 五月丁香综合缴情六月小说| 94人妻少妇偷人精品| 99久久亚洲综合精品成人网| 国产精品白浆免费视频| 国内精品久久黄色三级乱| 亚洲国产性夜夜综合| 欧洲美女黑人粗性暴交视频| 综合久久av一区二区三区| 国产另类ts人妖一区二区| 国产欧美在线一区二区三| 久久国产热这里只有精品| 国产360激情盗摄全集| 人人妻人人澡人人爽人人精品av| 苍井空一区二区波多野结衣av| 久热久热免费在线观视频| 狠狠亚洲色一日本高清色| 精品一区二区不卡无码AV| 亚洲av成人一区二区| 男女18禁啪啪无遮挡激烈网站| 亚洲av无在线播放中文| 日日摸夜夜添狠狠添欧美| 欧美成人性色一区欧美成人性色区| 一二三四中文字幕日韩乱码| 亚洲综合网中文字幕在线| 国产在线乱子伦一区二区| 少妇熟女久久综合网色欲| 精品综合一区二区三区四区| 免费观看全黄做爰大片| 国产肥妇一区二区熟女精品| 欧美变态另类zozo| 国产一区二区三区乱码在线观看| 国产精品一区二区传媒蜜臀| 日韩中文字幕精品人妻| 武陟县| 99久久国产综合精品色|