jmeter响应断言_如何对流利的断言模式进行测试重构?

jmeter响应断言

jmeter响应断言

什么是清洁测试?

清洁代码规则同样适用于生产代码和测试代码。 每次都进行代码清理,包括编写测试时。 在添加新测试之后甚至在编写新测试之前,您通常会发现重构的机会。 当新测试需要其他测试中已经包含的部件(例如断言或系统配置)时,就会是这种情况。

此类调整应考虑到《清洁法规》的基本原则。 它们主要涉及保持可读性和保持引入进一步更改的便利性。 我们还应该确保代码能够快速阅读和理解。

重构示例

以下是一些集成测试的集合。 他们检查访问健身俱乐部(健身房,桑拿浴室,游泳池)的价格表。 该逻辑还包括忠诚度积分的计算。

尽管此测试的示例很短,但它已经包含一些代码重复项。 在每个测试用例的开头和结尾都可以找到重复的代码。

 @Test
 public void twoHours_isOnly_payEntryFee() {

  Facility beFitGym = new Facility( "Be Fit Gym" , Facility.GYM);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // when

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[1]" )

    .isEqualTo( "Be Fit Gym" );
        
  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[2]" )

    .isEqualTo( "4.0" );
        
  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[3]" )

    .isEqualTo( "100" );
 }
 @Test
 public void twoHours_PayForEach() {

  // Given

  Facility beFitGym = new Facility( "Jacuzzi" , Facility.STEAM_BATH);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // When

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertThat(payment)

   .valueByXPath( "/table/tr[1]/td[1]" )

   .isEqualTo( "Be Fit Jacuzzi" );
        
  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[2]" )

    .isEqualTo( "10.0" ); 
  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[3]" )

    .isEqualTo( "300" );
 }

一步一步重构

格式

在进行第一次转换之前,请注意代码格式化的价值。 上面的代码已经被格式化。 在此之前,它看起来像下面的代码。 当代码更清晰时,您可能会看到区别?

 @Test
 public void twoHours_PayForEach() {

  ...

  assertThat(payment).valueByXPath( "/table/tr[1]/td[1]" ).isEqualTo( "Gym" );

  assertThat(payment).valueByXPath( "/table/tr[1]/td[2]" ).isEqualTo( "10.0" );

  assertThat(payment).valueByXPath( "/table/tr[1]/td[3]" ).isEqualTo( "300" );
 }

使断言取决于局部变量

在格式良好的代码中,代码重复更为明显。 这就是我准备代码以提取包含逻辑重复的方法的方式。 在执行方法提取之前,我将通过提取重复代码使它们依赖于局部变量。

 @Test
 public void twoHours_payEntryFee() {

  // Given

  Facility beFitGym = new Facility( "Be Fit Gym" , Facility.GYM);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // When

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  String facilityName = "Be Fit Gym" ;

  String facilityPrice = "4.0" ;

  String facilityPoints = "100" ; 
  assertThat(payment)

   .valueByXPath( "/table/tr[1]/td[1]" )

   .isEqualTo(facilityName);
        
  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[2]" )

    .isEqualTo(facilityPrice);

  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[3]" )

    .isEqualTo(facilityPoints);
 }

提取断言方法

现在该提取方法了。 在大多数Java开发环境中,这是一种自动代码重构。

 private void assertFacility(String payment,

    String facilityName,

    String facilityPrice,

    String facilityPoints) {
   
  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[1]" )

    .isEqualTo(facilityName);

  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[2]" )

    .isEqualTo(facilityPrice);

  assertThat(payment)

    .valueByXPath( "/table/tr[1]/td[3]" )

    .isEqualTo(facilityPoints);
 }

不再需要提取的局部变量,因此我们可以内联它们。 以下是此测试重构的结果。

 @Test
 public void twoHours_isOnly_payEntryFee() {

  Facility beFitGym = new Facility( "Be Fit Gym" , Facility.GYM);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // when

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertFacility(payment, "Be Fit Gym" , 4.0 , 100 );
 }
 @Test
 public void twoHours_PayForEach() {

  // Given

  Facility beFitGym = new Facility( "Jacuzzi" , Facility.STEAM_BATH);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // When

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertFacility(payment, "Jacuzzi" , 10.0 , 150 );
 }

注意方法的参数

请注意,测试变得更短了。 但是,现在的问题是另外属于两个组的参数的数量。 第一组是输入数据(第一个参数),第二组是每个断言的值(接下来的三个参数)。 此外,如果彼此相邻的参数属于同一类型,则很容易混淆其顺序。

创建一个新的断言类

接下来,我将使用以上两组参数作为后续更改的方向。 我将方法放在一个新类中,并将其中一个组定义为构造函数参数。 然后,当前方法将仅包含来自第二组的参数,并将通过类字段访问第一组。

Dokonaj ektrakcji klasy poprzezekstrakcjędelegata

为了创建一个新类,我启动了“提取委托”代码重构,这是IntelliJ IDE中Java语言的另一种自动转换。

这是代码转换的结果。

 private final FacilityAssertion facilityAssertion = new FacilityAssertion();
 @Test
 public void twoHours_isOnly_payEntryFee() {

  Facility beFitGym = new Facility( "Be Fit Gym" , Facility.GYM);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // when

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  facilityAssertion.assertFacility(payment, "Be Fit Gym" , 4.0 , 100 );
 }
 @Test
 public void twoHours_PayForEach() {

  // Given

  Facility beFitGym = new Facility( "Jacuzzi" , Facility.STEAM_BATH);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // When

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  facilityAssertion.assertFacility(payment, "Jacuzzi" , 10.0 , 150 );
 }

内联字段

课堂上多余的部分不是我的目标。 所以我正在吸收这个领域。 然后,无论逻辑在何处使用该字段,都会从头开始重新创建新的断言对象。

 @Test
 public void twoHours_isOnly_payEntryFee() {

  Facility beFitGym = new Facility( "Be Fit Gym" , Facility.GYM);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // when

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  new FacilityAssetion().assertFacility(payment, "Be Fit Gym" , 4.0 , 100 );
 }
 @Test
 public void twoHours_PayForEach() {

  // Given

  Facility beFitGym = new Facility( "Jacuzzi" , Facility.STEAM_BATH);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // When

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  new FacilityAssetion().assertFacility(payment, "Jacuzzi" , 10.0 , 150 );
 }

然后,我重新提取“ assertFacility”方法。 由于这一点,调用断言构造器将只在一个地方。 低于重构结果。

 private void assertFacility(String payment, String facilityName,

      String facilityPrice, String facilityPoints) {

        new FacilityAssertion()

          .assertFacility(payment, facilityName,

                          facilityPrice, facilityPoints);

    }
 @Test
 public void twoHours_isOnly_payEntryFee() {

  Facility beFitGym = new Facility( "Be Fit Gym" , Facility.GYM);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // when

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertFacility(payment, "Be Fit Gym" , 4.0 , 100 );
 }
 @Test
 public void twoHours_PayForEach() {

  // Given

  Facility beFitGym = new Facility( "Jacuzzi" , Facility.STEAM_BATH);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // When

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertFacility(payment, "Jacuzzi" , 10.0 , 150 );
 }

将参数从方法移至构造函数

当前仅从一个位置调用构造函数(FacilityAssertion)。 因此,我在构造函数中添加了一个新参数,然后在此类中添加了一个字段。 当该方法使用“付款”字段而不是“付款”参数时–我可以删除不必要的参数。

用静态方法调用替换构造函数

接下来,在FacilityAssertion类中,我运行自动代码转换“用静态方法替换构造函数调用”。

 public class FacilityAssertion {

  private String payment; 
  private FacilityAssertion(String payment) {

     this .payment = payment;

  }

  public static FacilityAssertion assertThat(String payment) {

      return new FacilityAssertion(payment);

  }

  void hasAttributes(String facilityName, String facilityPrice,

     String facilityPoints) {

    XmlAssert.assertThat( this .payment)

      .valueByXPath( "/table/tr[1]/td[1]" )

      .isEqualTo(facilityName);

    XmlAssert.assertThat( this .payment)

      .valueByXPath( "/table/tr[1]/td[2]" )

      .isEqualTo(facilityPrice);

    XmlAssert.assertThat( this .payment)

      .valueByXPath( "/table/tr[1]/td[3]" )

      .isEqualTo(facilityPoints);

  }
 }

用方法链替换方法

是时候建立方法链了。 因此,我最后提取了一些新方法,这些方法将在其末尾包含“ return this”。 这将使我能够将这些方法的代码重构成一个调用链。

 public class FacilityAssertion {

  private String payment; 
  private FacilityAssertion(String payment) {

    this .payment = payment;

  }

  public static FacilityAssertion assertThat(String payment) {

    return new FacilityAssertion(payment);

  }

  FacilityAssertion hasAttributes(String facilityName,

    String facilityPrice,

    String facilityPoints) {

      return hasName(facilityName)

              .hasPrice(facilityPrice)

              .hasPoints(facilityPoints);

  }

  FacilityAssertion hasPoints(String facilityPoints) {

    XmlAssert.assertThat( this .payment)

      .valueByXPath( "/table/tr[1]/td[3]" )

      .isEqualTo(facilityPoints);

    return this ;

  }

  FacilityAssertion hasPrice(String facilityPrice) {

    XmlAssert.assertThat( this .payment)

     .valueByXPath( "/table/tr[1]/td[2]" )

     .isEqualTo(facilityPrice);

    return this ;

  }

  FacilityAssertion hasName(String facilityName) {

    XmlAssert.assertThat( this .payment)

     .valueByXPath( "/table/tr[1]/td[1]" )

     .isEqualTo(facilityName);

    return this ;

  }
 }

内联初始断言方法

 @Test
 public void twoHours_isOnly_payEntryFee() {

  Facility beFitGym = new Facility( "Be Fit Gym" , Facility.GYM);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // when

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertThat(payment)

    .hasName( "Be Fit Gym" )

    .hasPrice( "4.0" )

    .hasPoints( "100" );
 }
 @Test
 public void twoHours_PayForEach() {

  // Given

  Facility beFitGym = new Facility( "Jacuzzi" , Facility.STEAM_BATH);

  Visit visit = new Visit(beFitGym, 2 );

  Client client = new Client( "Mike" ); 
  // When

  client.addVisit(visit);

  String payment = client.getReceipt();

  // Then

  assertThat(payment)

    .hasName( "Jacuzzi" )

    .hasPrice( "10.0" )

    .hasPoints( "150" );
 }

类似地使用构建器或工厂模式进行测试设置

您肯定已经注意到,现在测试配置仅在设施类型和访问持续时间上有所不同。 返回的设施名称始终相同,因此您可以单独检查一次,并且只能检查一次。

 @Test
 public void twoHours_isOnly_payEntryFee() {

  // Given

  String payment = newPaymentFor(Facility.GYM, 2 ); 
  // Then

  assertThat(payment)

    .hasPrice( "4.0" )

    .hasPoints( "100" );
 }
 @Test
 public void twoHours_PayForEach() {

  // Given

  String payment = newPaymentFor(Facility.STEAM_BATH, 2 ); 
  // Then

  assertThat(payment)

    .hasPrice( "10.0" )

    .hasPoints( "150" );
 }

如您所见,我们将上面的代码重构为干净的测试。 它们没有代码重复并且易于理解。 编写另一个测试也很简单。

图书馆促进流利的建设者模式

测试库支持流利的断言模式。 其中之一是asserjJ ,它与JUnit很好地兼容。 它遵循流畅的构建器模式,并允许一次创建一个断言。 它有助于在测试失败的情况下编写一条详细的消息,或者返回检查更多内容的新嵌套断言实例。

注意测试的可读性

鲍伯叔叔曾经说过(或写过):“像一流公民一样对待考试。” 因此,请通过不断重构来照顾您的测试! 清洁代码也是清洁测试!

请记住,重构金字塔的概念和SOLID原则同样适用于通过重构进行的清洁测试。

翻译自: https://www.javacodegeeks.com/2020/08/how-to-do-test-refactoring-towards-fluent-assertion-pattern.html

jmeter响应断言

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值