*TestNG


一、Eclipse 中安装 、使用TestNG

1、在线安装

  • 首先打开 Eclipse,点击菜单栏:Help ->Install New Software;
  • 点击“Add…”按钮,弹出 Add Repository 窗口,输入 name 和 location ;
  • Name:TestNG
  • location:http://beust.com/eclipse
  • 然后,勾选 testNG,点击“Next”进行安装 ;
    这里写图片描述
  • 下载完成,点击“Next >” 根据提示完成安装 ;

2、离线安装

  • testNG官网:http://testng.org/doc/
    点开之后点击“download”
    这里写图片描述

  • 点开链接: http://beust.com/eclipse

这里写图片描述

  • 选择某一版本,点击下载;
  • 将解压缩的文件夹放到eclipse的dropin目录下,重启eclipse;
  • 打开Eclipse,新建-other,选择“TestNG——>TestNG Class”,有这个就成功了;

3、安装TestNG之后,导入jar

4、创建TestNG单元测试项目

new --> other --> TestNG --> 确定


二、TestNG 注释

API:http://testng.org/doc/documentation-main.html

|注 解| 描 述|
|-|
|@BeforeSuite|注解的方法将只运行一次,在该套件中所有测试运行之前运行|
|@AfterSuite |注解的方法将只运行一次,在此套件中运行所有测试之后运行|
|@BeforeTest |带注释的方法将在所有属于<test>标记中的类的测试方法运行之前运行。|
|@AfterTest |带注释的方法将在所有属于<test>标记内的类的测试方法运行之后运行。|
|@BeforeClass |在调用当前类中的第一个测试方法之前,将运行带注释的方法|
|@AfterClass |在运行当前类的所有测试方法之后,将运行带注释的方法|
|@BeforeGroups |这个配置的组列表方法将先运行。这个方法保证在第一个测试方法被调用之前运行。|
|@AfterGroups |这个配置的组列表方法将最后运行。这个方法保证在最后一个测试方法被调用之后运行。|
|@BeforeMethod |在每个测试方法之前运行。|

@AfterMethod在每个测试方法之后运行。
@DataProvider标记方法为测试方法提供数据。带注释的方法必须返回一个对象[][],其中每个对象[]可以被分配到测试方法的参数列表。想要从这个DataProvider中接收数据的@Test方法需要使用DataProvider名称,它等于这个注释的名称。
@Factory标记一个方法作为一个工厂,返回将被TestNG用作测试类的对象。该方法必须返回对象[]。
@Listeners在测试类中定义侦听器。
@Parameters用于为测试方法传递参数
@Test标记一个类或方法作为测试的一部分。

上述的注解分为Before类别和After类,我们可以在Before类别的注解方法里面做一些初始化动作,如实例化数据库连接、新建数据库连接池、创建线程池、打开文件流等等;在After类别的注解方法里面做一些销毁动作,如释放数据库连接、销毁数据库连接池、销毁线程池或者关闭文件流等等。同一类别的不同注解会在不同的位置被调用;

beforeSuite-1
beforeSuite-2
		beforeTest-1
		beforeTest-2
				beforeClass-1
						beforeMethod-1
								test1-1
						afterMethod-1
						beforeMethod-1
								test2-1
						afterMethod-1
				afterClass-1
				
				beforeClass-2
						beforeMethod-2
								test1-2
						afterMethod-2
						beforeMethod-2
								test2-2
						afterMethod-2
				afterClass-2
		afterTest-1
		afterTest-2
afterSuite-1
afterSuite-1

我们可以根据自身需求,选择特定的位置去执行一些初始化动作/销毁动作,以及一些销毁动作:

  • 假如你需要针对整个测试suite做初始化动作,那么应该选择在被@BeforeSuite注解的方法里面执行
  • 如果需要针对一个<test>里面的所有测试类做初始化动作,那么可以选择在被@BeforeTest注解的方法里面执行
  • 假如你想在每一个测试方法执行前做初始化动作,那么应该选择@BeforeMethod

@Test 注解

@Test 注解是TestNG的核心注解,被打上该注解的方法,表示为一个测试方法

这个注解有多个配置属性,用法为:@Test(param1 = …, param2 = …)
|属性|描述|
|–|
|alwaysRun | 如果设置为true,这个测试方法将始终运行,即使它依赖的前置测试方法失败|
|dataProvider | 选定传入参数的构造器。此测试方法的数据提供程序的名称。|
|dataProviderClass |确定参数构造器的Class类。(参数构造器首先会在当前测试类里面查找,如果参数构造器不在当前测试类定义,那么必须使用该属性来执行它所在的Class类)|
|dependsOnGroups|确定依赖的前置测试组别。|
|dependsOnMethods | 确定依赖的前置测试方法。|
|description |测试方法描述信息。(建议为每个测试方法添加有意义的描述信息,这将会在最后的报告中展示出来)|
|enabled | 默认为true,如果指定为false,表示不执行该测试方法。|
|expectedExceptions |指定期待测试方法抛出的异常,多个异常以逗号(,)隔开。|
|groups| 指定该测试方法所属的组,可以指定多个组,以逗号隔开。组测试的用法将在后面文章单独介绍。|
|invocationCount | 指定测试方法需要被调用的次数。|
|invocationTimeOut| 每一次调用的超时时间,如果invocationCount没有指定,该参数会被忽略。应用场景可以为测试获取数据库连接,超时就认定为失败。单位是毫秒。|
|priority | 指定测试方法的优先级,数值越低,优先级越高,将会优先于其他数值高的测试方法被调用。(注意是针对一个测试类的优先级)|
|timeout | 指定整个测试方法的超时时间。单位是毫秒。|

@Parameters 注解:用于为测试方法传递参数

public class AnnotationParametersTest {
    @Parameters(value = {"param1", "param2"})
    @Test
    public void test(String arg1, String arg2) {
        System.out.println("use @Parameters to fill method arguments : arg 1 = " + arg1 + ", arg2 = " + arg2);
    }
}

testng.xml配置

<test name="testAnnotationParameters">
    <parameter name="param1" value="value1"></parameter>
    <parameter name="param2" value="value2"></parameter>
    <classes>
        <class name="com.crazypig.testngdemo.AnnotationParametersTest" />
    </classes>
</test>

输出结果:

use @Parameters to fill method arguments : arg 1 = value1, arg2 = value2

@DataProvider 注解

@Parameters注解可以为测试方法传递参数,但是这种方式参数值需要配置在testng.xml里面,灵活性不高。而**@DataProvider注解**同样可以为测试方法传递参数值,并且,它是真正意义上的参数构造器,可以传入多组测试数据对测试方法进行测试。被@DataProvider注解的方法,方法返回值必须为Object[][]或者Iterator<Object[]>。

public class AnnotationDataProviderTest {
    @DataProvider(name="testMethodDataProvider")
    public Object[][] testMethodDataProvider() {     //方法返回值必须为Object[][]或者Iterator<Object[]>
        return new Object[][]{{"value1-1", "value2-1"}, {"value1-2", "value2-2"}, {"value1-3", "value2-3"}};
    }
    @Test(dataProvider="testMethodDataProvider")
    public void test(String arg1, String arg2) {
        System.out.println("use @DataProvider to fill method argument : arg1 = " + arg1 + " , arg2 = " + arg2);
    }
}

testng.xml配置:

<test name="testDataProvider">
  <classes>
    <class name="com.crazypig.testngdemo.AnnotationDataProviderTest" />
  </classes>
</test>

运行结果:

use @DataProvider to fill method argument : arg1 = value1-1 , arg2 = value2-1
use @DataProvider to fill method argument : arg1 = value1-2 , arg2 = value2-2
use @DataProvider to fill method argument : arg1 = value1-3 , arg2 = value2-3

@Factory 注解

在一个方法上面打上@Factory注解,表示该方法将返回能够被TestNG测试的测试类。利用了设计模式中的工厂模式。

public class AnnotationFactoryTest {
    @Factory
    public Object[] getSimpleTest() {
        return new Object[]{ new SimpleTest("one"), new SimpleTest("two")};
    }
}
public class SimpleTest {
    private String param;
    public SimpleTest(String param) {
        this.param = param;
    }
    @Test
    public void test() {
        System.out.println("SimpleTest.param = " + param);
    }
}

testng.xml配置:

<test name="testFactory">
    <classes>
        <class name="com.crazypig.testngdemo.AnnotationFactoryTest" />
    </classes>
</test>

运行结果:

SimpleTest.param = one
SimpleTest.param = two

@Listeners 注解

一般我们写测试类不会涉及到这种类型的注解,这个注解必须定义在类、接口或者枚举类级别。实用的Listener包括ISuiteListener、ITestListener和IInvokedMethodListener,他们可以在suite级别、test级别和test method一些执行点执行一些自定义操作,如打印日志。


三、testng.xml 文件

TestNG 与 Junit 比较大的一个差异就是前者通过 testng.xml 文件来配置测试用例的执行。testng.xml 文件可以很好的控制要执行的测试用例的粒度,即测试包,测试类,测试方法。

  • TestNG 官方文档:http://testng.org/doc/documentation-main.html

testng.xml

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
	<test name="Nopackage" >
		<classes>
			<class name="NoPackageTest" />
		</classes>
	</test>
	<test name="Regression1">
		<classes>
			<class name="test.sample.ParameterSample"/>
			<class name="test.sample.ParameterTest"/>
		</classes>
	</test>
</suite>

你可以指定包名称代替类名:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > 
<suite name="Suite1" verbose="1" >
  <test name="Regression1"   >
    <packages>
      <package name="test.sample" />
   </packages>
 </test>
</suite>

在本例中,TestNG将查看test.sample包中的所有类,并且只保留有TestNG注释的类。
你还可以指定包含和排除的组和方法:

<test name="Regression1">
  <groups>
    <run>
      <exclude name="brokenTests"  />      //排除不执行的测试用例
      <include name="checkinTests"  />     //指定执行的测试用例
    </run>
  </groups>  

  <classes>
    <class name="test.IndividualMethodsTest">
      <methods>
        <include name="testMethod" />
      </methods>
    </class>
  </classes>
</test>

你还可以在 testng.xml 中定义新的组。并在属性中指定额外的细节,比如是否并行运行测试、使用多少线程、是否运行JUnit测试等等……
在默认情况下,TestNG将按照在XML文件中找到的顺序运行测试。如果您希望在这个文件中列出的类和方法以不可预测的顺序运行,则将preserve-order属性设置为false。

<test name="Regression1" preserve-order="false">
	<classes>
		<class name="test.Test1">
			<methods>
				<include name="m3" />
				<include name="m1" />
				<include name="m2" />
			</methods>
		</class>
		
		<class name="test.Test2" />
	</classes>
</test>

preserve-order 参数用于控制测试用例的执行顺序。

  • 如果为:Ture,测试用例的顺序为:m3 > m1 > m2;
  • 如果为 :false,那么默认会按照用例的名称的有字母/数字的顺序执行:m1 > m2 > m3;

多线程执行测试用例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="suite1" parallel="classes" thread-count="2" >
	<test verbose="2" name="test1">
		<classes>
			<class name="com.testng.test.testBaidu"/>
			<class name="com.testng.test.testYoudao"/>
		</classes>
	</test>
</suite>
  • parallel 表示你需要对哪个级别进行多线程;
  • thread-count 用于指定线程的个数;

参考:
parallel=“methods” 每个方法都将采用独立的线程进行测试;
parallel=“classes” 将把每个<class>标签内的所有方法在同一个线程中执行,但是<classes>中的不同<class>将会以不同的线程执行;
parallel=“instances” TestNg 将把同一个实例内的所有方法运行在同一个线程中,但是如果两个方法是在不同的实例中,那么他们将会在不同的线程中执行;


四、运行测试用例、查看测试结果

在运行测试用例之前,我们首先要用 TestNG 编写一个单元测试用例,我们以百度搜索为例,代码如下:

testBaidu.java

package com.testng.test;
import ......

public class testBaidu {
	private WebDriver driver;
	private String baseUrl;
	
	@BeforeClass
	public void setUp() throws Exception {
		driver = new ChromeDriver();
		baseUrl = "https://www.baidu.com/";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}
	@Test
	public void testCase() throws Exception {
		driver.get(baseUrl + "/");
		driver.findElement(By.id("kw")).sendKeys("testNG");
		driver.findElement(By.id("su")).click();
		Thread.sleep(2000);
		String title =driver.getTitle();
		assertEquals(title,"testNG_百度搜索");
	}
	@AfterClass
	public void tearDown() throws Exception {
		driver.quit();
	}
}

TestNG 的运行测试用例有3种方法:

(1)方法一:通过class来执行:
org.testng.TestNG testng = new org.testng.TestNG();
testng.setTestClasses(new Class[]{TestCaseMonitor.class});
testng.run();

新建一个TestNG对象,setTestClass传递一个用例的class进去,然后执行用例run();

(1)方法二

在测试用例文件右键,选择 Run As —> TestNG Test 运行;
这里写图片描述

注意:若直接在绿色框里的文件名处右击“run as ”无选项,因为没有主函数;需要在红色框 testCase() 处右击运行;

(2)方法三

创建 testng.xml 配置文件;其实方法一也需要 xml 配置文件,只是 TestNG 默认帮我们创建了一个 testng-customsuite.xml,该文件的路径在上面的运行结果中;

在包中右键,选择创建 file;输入文件名为 testng.xml,默认一般就叫这名;点击“Finish”完成文件的创建;

testng.xml 配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="suite1">
	<test verbose="2" name="test1">
		<classes>
			<class name="com.testng.test.testBaidu"/>
		</classes>
	</test>
</suite>

在 testng.xml 文件中右键 Run As —> TestNG Test 运行;


TestNG 默认会在项目的目录下生成测试报告: .../WorkSpace\myPro\test-output/emailable-report.html

这里写图片描述


五、TestNG 测试技巧

1、依赖性测试

JUnit 框架想达到的一个目标就是测试隔离。

它的缺点是:人们很难确定测试用例执行的顺序,而这对于任何类型的依赖性测试都非常重要。开发者们使用了多种技术来解决这个问题,例如,按字母顺序指定测试用例,或是更多地依靠 fixture 来适当地解决问题。如果测试成功,这些解决方法都没什么问题。但是,如果测试不成功,就会产生一个很麻烦的后果: 所有后续的依赖测试也会失败。在某些情况下,这会使大型测试套件报告出许多不必要的错误。

例如:假设有一个测试套件测试一个需要登录的 Web 应用程序。您可以创建一个有依赖关系的方法,通过登录到这个应用程序来创建整个测试套件,从而避免 JUnit 的隔离机制。这种解决方法不错,但是如果登录失败, 即使登录该应用程序后的其他功能都正常工作,整个测试套件依然会全部失败!

跳过,而不是标为失败!

与 JUnit 不同,TestNG 利用 Test 注释的 dependsOnMethods 属性来应对测试的依赖性问题。有了这个便利的特性,就可以轻松指定依赖方法。例如,前面所说的登录将在某个方法之前运行。此外,如果依赖 方法失败,它将被跳过,而不是标记为失败。

这个特性就非常有用了,例 126 邮箱的测试,用例都基于登录邮箱之后的验证,如果验证登录的用例失败了,那么登录邮箱收发邮件的用例其实也没必要运行了。

testMail.java

package com.testng.test;
import ......

public class testMail {
	public static void login(WebDriver driver,String username,String password){   //登录方法
		driver.findElement(By.id("idInput")).clear();
		driver.findElement(By.id("idInput")).sendKeys(username);
		driver.findElement(By.id("pwdInput")).clear();
		driver.findElement(By.id("pwdInput")).sendKeys(password);
		driver.findElement(By.id("loginBtn")).click();
	}
	
	public static void logout(WebDriver driver){         //退出方法
		driver.findElement(By.linkText("退出")).click();
	}
	
	@Test
	public void verifyLogin() {                    //验证登录测试用例
		WebDriver driver = new ChromeDriver();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
		driver.get("http://www.126.com");
		
		String username = "testingwtb";
		String password = "a123456";
		
		login(driver,username,password);                //调用登录方法
		String text = driver.findElement(By.id("spnUid")).getText();
		assertEquals(text,"testingwtb@126.com");
		logout(driver);                                 //调用退出方法
		driver.quit();
	}
	@Test (dependsOnMethods = {"verifyLogin"})          //这个测试用例是否执行取决于verifyLogin方法
	public void verifySearchMail() {
		WebDriver driver = new ChromeDriver();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
		driver.get("http://www.126.com");
	 
		String username = "testingwtb";
		String password = "a123456";
		login(driver,username,password);
		//搜索
		WebElement search =	driver.findElement(By.xpath("//input[@class='nui-ipt-input' and @type='text']"));
		search.sendKeys("小明");
		search.sendKeys(Keys.ENTER);
		String text = driver.findElement(By.className("nui-title-text")).getText();
		System.out.println(text);
		assertEquals(text,"搜索结果");
		logout(driver);
		driver.quit();
	}
}

上面的例子中定义了两个测试:一个验证登录,另一个验证账户信息。请注意,通过使用 Test 注释的dependsOnMethods={“verifyLogin”}子句,verifyAccountInfo 测试指定了它依赖 verifyLogin()方法。

2、忽略测试

有时候测试用例还没准备好,可以给测试用例加上**@Test(enable = false)**,用来禁止此测试用例;
testMail.java

package com.testng.test;
import ......

public class testMail {
	public static void login(WebDriver driver,String username,String password){ 	//登录方法
		driver.findElement(By.id("idInput")).clear();
		driver.findElement(By.id("idInput")).sendKeys(username);
		driver.findElement(By.id("pwdInput")).clear();
		driver.findElement(By.id("pwdInput")).sendKeys(password);
		driver.findElement(By.id("loginBtn")).click();
	}
	
	public static void logout(WebDriver driver){              //退出方法
		driver.findElement(By.linkText("退出")).click();
	}
	
	@Test(enabled = false)                                    //忽略这条用例 
	public void verifyLogin() { 
		WebDriver driver = new ChromeDriver();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
		driver.get("http://www.126.com");
		String username = "testingwtb";
		String password = "a123456";
		login(driver,username,password);
		String text = driver.findElement(By.id("spnUid")).getText();
		assertEquals(text,"testingwtb@126.com");
		logout(driver);
		driver.quit();
	}
}

3、参数化测试

TestNG 中另一个有趣的特性是参数化测试。

在 JUnit 中,如果您想改变某个受测方法的参数组,就只能给每个不同的参数组编写一个测试用例。多数情况下,这不会带来太多麻烦。然而,我们有时会碰到一些情况,对其中的业务逻辑,需要运行的测试数目变化范围很大。在这样的情况下,使用 JUnit 的测试人员往往会转而使用 FIT(验收测试框架)这样的框架,因为这样就可以用表格数据驱动测试。但是 TestNG 提供了开箱即用的类似特性。

通过在 TestNG 的 XML 配置文件中放入参数化数据,就可以对不同的数据集重用同一个测试用例,甚至有可能会得到不同的结果。这种技术完美地避免了只能假定一切正常的测试,或是没有对边界进行有效验证的情况。

Eg1 : 通过 testng.xml 传递参数给测试代码

testBaidu.java

package com.testng.test;
import ......

public class testBaidu {
	private WebDriver driver;
	private String baseUrl;
	
	@BeforeClass
	public void setUp() throws Exception {
		driver = new ChromeDriver();
		baseUrl = "https://www.baidu.com/";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}
	@Test
	@Parameters("test1")       //设置测试方法的入参
	public void testCase(String test1) throws Exception {
		driver.get(baseUrl + "/");
		System.out.println("sreach key value:"+ test1);
		driver.findElement(By.id("kw")).sendKeys(test1);
		driver.findElement(By.id("su")).click();
		Thread.sleep(2000);
		String title =driver.getTitle();
		assertEquals(title,test1+"_百度搜索");
	}
	@AfterClass
	public void tearDown() throws Exception {
		driver.quit();
	}
}

对应的 testng.xml 文件配置如下:
testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="suite1">
	<parameter name="test1" value="testng" />     //定义 test1 的 value 
	<test name="test1">
		<classes>
			<class name="com.testng.test.testBaidu"/>
		</classes>
	</test>
</suite>

Eg2 : 通过 DataProvider 传递参数
testng.xml

package com.testng.test;
import ......

public class mailLogin {
	private WebDriver driver;
	private String baseUrl;
	
	@BeforeClass
	public void setUp() throws Exception {
		driver = new ChromeDriver();
		baseUrl = "http://www.126.com";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}
	 
	@DataProvider(name="user")             //定义对象数组
	public Object[][] Users(){
		return new Object[][]{
			{"testingwtb","a123456"},
		};
	}
	
	@Test(dataProvider="user")             //调用 user 数组的值
	public void testCase(String username,String password) throws Exception {
		driver.get(baseUrl);
		driver.findElement(By.id("idInput")).clear();
		driver.findElement(By.id("idInput")).sendKeys(username);
		driver.findElement(By.id("pwdInput")).clear();
		driver.findElement(By.id("pwdInput")).sendKeys(password);
		driver.findElement(By.id("loginBtn")).click();
		Thread.sleep(2000);
		String text = driver.findElement(By.id("spnUid")).getText();
		assertEquals(text,username+"@126.com");
	}
	@AfterClass
	public void tearDown() throws Exception {
		driver.quit();
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蛋白质是生物体中普遍存在的一类重要生物大分子,由天然氨基酸通过肽键连接而成。它具有复杂的分子结构和特定的生物功能,是表达生物遗传性状的一类主要物质。 蛋白质的结构可分为四级:一级结构是组成蛋白质多肽链的线性氨基酸序列;二级结构是依靠不同氨基酸之间的C=O和N-H基团间的氢键形成的稳定结构,主要为α螺旋和β折叠;三级结构是通过多个二级结构元素在三维空间的排列所形成的一个蛋白质分子的三维结构;四级结构用于描述由不同多肽链(亚基)间相互作用形成具有功能的蛋白质复合物分子。 蛋白质在生物体内具有多种功能,包括提供能量、维持电解质平衡、信息交流、构成人的身体以及免疫等。例如,蛋白质分解可以为人体提供能量,每克蛋白质能产生4千卡的热能;血液里的蛋白质能帮助维持体内的酸碱平衡和血液的渗透压;蛋白质是组成人体器官组织的重要物质,可以修复受损的器官功能,以及维持细胞的生长和更新;蛋白质也是构成多种生理活性的物质,如免疫球蛋白,具有维持机体正常免疫功能的作用。 蛋白质的合成是指生物按照从脱氧核糖核酸(DNA)转录得到的信使核糖核酸(mRNA)上的遗传信息合成蛋白质的过程。这个过程包括氨基酸的活化、多肽链合成的起始、肽链的延长、肽链的终止和释放以及蛋白质合成后的加工修饰等步骤。 蛋白质降解是指食物中的蛋白质经过蛋白质降解酶的作用降解为多肽和氨基酸然后被人体吸收的过程。这个过程在细胞的生理活动中发挥着极其重要的作用,例如将蛋白质降解后成为小分子的氨基酸,并被循环利用;处理错误折叠的蛋白质以及多余组分,使之降解,以防机体产生错误应答。 总的来说,蛋白质是生物体内不可或缺的一类重要物质,对于维持生物体的正常生理功能具有至关重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值