软件测试

编写测试用例及一个例子

http://www.51testing.com/html/24/n-3727424.html

 

软件需求3个层次――业务需求、用户需求和功能需求

软件需求包括3个不同的层次――业务需求、用户需求和功能需求。除此之外,每个系统还有各种非功能需求。 
业务需求(Business requirement)表示组织或客户高层次的目标。业务需求通常来自项目投资人、购买产品的客户、实际用户的管理者、市场营销部门或产品策划部门。业务需求描述了组织为什么要开发一个系统,即组织希望达到的目标。使用前景和范围(vision and scope)文档来记录业务需求,这份文档有时也被称作项目轮廓图或市场需求(project charter 或 market requirement)文档。 
用户需求(user requirement)描述的是用户的目标,或用户要求系统必须能完成的任务。用例、场景描述和事件――响应表都是表达用户需求的有效途径。也就是说用户需求描述了用户能使用系统来做些什么。 
功能需求(functional requirement)规定开发人员必须在产品中实现的软件功能,用户利用这些功能来完成任务,满足业务需求。功能需求有时也被称作行为需求(behavīoral requirement),因为习惯上总是用“应该”对其进行描述:“系统应该发送电子邮件来通知用户已接受其预定”。功能需求描述是开发人员需要实现什么。 
系统需求(system requirement)用于描述包含多个子系统的产品(即系统)的顶级需求。系统可以只包含软件系统,也可以既包含软件又包含硬件子系统。人也可以是系统的一部分,因此某些系统功能可能要由人来承担。


业务规则括企业方针、政府条例、工业标准、会计准则和计算方法等。业务规划本身并非软件需求,因为它们不属于任何特定软件系统的范围。然而,业务规则常常会限制谁能够执行某些特定用例,或者规定系统为符合相关规则必须实现某些特定功能。有时,功能中特定的质量属性(通过功能实现)也源于业务规则。所以,对某些功能需求进行追溯时,会发现其来源正是一条特定的业务规则。 
功能需求记录在软件需求规格说明(SRS)中。SRS完整地描述了软件系统的预期特性。SRS我们一般把它当作文档,其实,SRS还可以是包含需求信息的数据库或电子表格;或者是存储在商业需求管理工具中的信息;而对于小型项目,甚至可能是一叠索引卡片。开发、测试、质量保证、项目管理和其他相关的项目功能都要用到 SRS。 
除了功能需求外,SRS中还包含非功能需求,包括性能指标和对质量属性的描述。

  
质量属性(quality attribute)对产品的功能描述作了补充,它从不同方面描述了产品的各种特性。这些特性包括可用性、可移植性、完整性、效率和健壮性,它们对用户或开发人员都很重要。其他的非功能需求包括系统与外部世界的外部界面,以及对设计与实现的约束。 
约束(constraint)限制了开发人员设计和构建系统时的选择范围。 
产品特性。所谓特性(feature),是指一组逻辑上相关的功能需求,它们为用户提供某项功能,使业务目标得以满足。对商业软件而言,特性则是一组能被客户识别,并帮助他决定是否购买的需求,也就是产品说明书中用着重号标明的部分。客户希望得到的产品特性和用户的任务相关的需求不完全是一回事。一项特性可以包括多个用例,每个用例又要求实现多项功能需求,以便用户能够执行某项任务。 
还有一项称为可用性(usability)的质量属性,它规定了业务需求中“有效”(efficiently)一词的含义。 
管理人员或市场营销人员负责定义软件的业务需求,以提高公司的运营效率(对信息系统而言)或产品的市场竞争力(对商业软件而言)。所有的用户需求都必须符合业务需求。需求分析员从用户需求中推导出产品应具备哪些对用户有帮助的功能。开发人员则根据功能需求和非功能需求设计解决方案,在约束条件的限制范围内实现必需的功能,并达到规定的质量和性能指标。 
当一项新的特性、用例或功能需求被提出时,需求分析员必须思考一个问题:“它在范围内吗?”。如果答案是肯定的,则该需求属于需求规格说明,反之则不属于。但答案也许是“不在,但应该在”,这时必须由业务需求的负责人或投资管理人来决定:是否扩大项目范围以容纳新的需求。这是一个可能影响项目进度和预算的商业决策。 
不属于需求的内容 
需求规格说明中不包括(除已知约束外的)设计和实现的细节、项目的计划信息,以及测试信息(Leffingwell 和 Widrig 2000)。把这些内容与需求分开,就可以把需求活动的注意力集中到了解开发小组需要开发的产品特性上。项目中通常还包括其他类型的需求,如开发环境需求,进度或预算限制,帮助新用户跟上进度的培训需求,或者发布产品使其转入支持环境的需求。这些都属于项目需求而不是产品需求,因此不属于软件需求的讨论范围。

举例如下:

业务需求一般是我由我们软件开发人员来搜集的,是企业自身在顾问等引导下自己所作的工作。我们只是去从他们那里直接的拿来就可以了。比如为了配合企业生产改造,为了加强库存管理,为了建立企业电子化运行平台,这些都是业务需求。这些东西的建模还是留给咨询顾问吧,我们没有拿那份企业流程重组的钱,也就不用费这个力气。 
用户需求是用户为实现其业务需求而提出的基于实际情况的具体目标。比如我的系统要可以查看库存中的零件数量,我需要可以由计算机给出投料方案,计算工资总额。 
功能需求就是要去解决这些具体的用户需求所产生的解决方案。这个就是我们平常说的需求说明。要得到这个就需要对用户需求作具体的分析,提出具体的实施方法。

需求调研步骤和方法

第1章前言

目的

需求调研是为需要说明书做前期工作,可以说需要说明书说是从需求调研表中得到或抽取而出。

需求调研是要了解现实世界中做实际工作的人们真正需要什么样的程序的过程,再把这些需求开进细节整理由设计部开发,再由销售部销售给用户。

用户:系统分析人员


第2章前期准备

2.1. 确定工具

  • 没有什么工具是好还是坏的问题,问题是关键是如何使用它们,无论是什么工具也只是一个辅助工具,也不是生成工具。
  • 工具的选取要求是自己(本组)熟悉的工具,不能是一件最新时髦工具而自己对它了解很少,结果大部分时间化在学习工具上,而不是使用它为你工作。
  • 工具最好也是要求是普通流行的,因为要考虑交流的问题。

2.2. 要做什么就要先了解什么

  • 如果做的项目是你所不了解的一个行业(专业)同组有要最好有要专家----最终用户做为这个专家是最好的,最少你有了解这个专业,不是要你成为专家,但最少要了解一定的专业知识(最少专来词汇你要知道),不然您甚至不知道去问什么问题或者如何去问他们,甚至于人家在说什么你也不知道。
  • 相应的专业资料是必须的,最少要有专业入门书籍和对应的资料,也需要求更深入的一些资料。当然有专家的参入就另当别论。
  • 如果行业的难度不是很大,可以通入分析人员的自我学习在短时间内了解行业,也许可以不用专家,否则专家是必须的。

2.3. 建立设计环境

一定建立一个专门的设计环境来为本项目服务,进行一定的资源分配,进行必要的文件管理。

2.4. 真正了解自己和用户

  • 那些是用户可能明确要达到的目地
  • 要知道那些是自己能做到的,那些是自己不能做的。
  • 对于不能做的处理方法,如拒绝,转包等
  • 那些是用户想要做到的

2.5. 列出人员分配表和所有工具列表

  • 明确项目人员分工
  • 统一项目所用的工具
  • 统一项目文件模版
  • 其它资源列表(资料,相关网站,资询电话。。。)

第3章调研过程

3.1. 搜集需求得到需求说明书

注意:

  1. 虽然最终必须要编成基于计算机解决方案的描述,但到目前为止,我们关注的焦点的文档在相应领域方面的部分。
  2. 记住这里没有计算机方面的行话,如果是编写一个会计软件,那么一位会计师都应该清楚地理解程序员写的会计方面的问题说明书
  3. 需求说明书问题中,不要太正式。只要描述能表达您想要做的事情就行了,就和另外一个人在说话一样就可以。
  4. 对于客户或相应人员了解问题时,一定要有记笔记的习惯,谈上几个小时,很多细节是记不住的。

3.2. 整理,检查和细化需求说明书

  1. 对于客户的需要进行必要的整理和分类有进从用户那里会得到很多信息,不行进必要的整理就不能从中进行合理的分析
  2. 分清有用功能、可选功能用、无用功能及不可实现功能对于用户来讲他可以说出他想要的很多功能,但这些功能间的关系有时是清晰的,但对于很多用户来讲想通过计算机或新系统实现他以前没有的功能,在这时他所提出的新需求的可行性和与其它模块之间的关系就已经不清,所以对于分析员来讲,要从用户的需求中分清有用功能和无用功能和可选功能,进行分别区分处理,比如不可实现功能请用户放弃。
  3. 不要忽略明显的错误用户倒是不经常提及他需要的东西,而这些东西对问题来说都是很基本的,要细化检查一定有注意这个问题。
  4. 你认为的也许不是对的对于系统分析员对需求分析的自认为的情况要加以注意,对于一个行业来说,有些规则可以不是最合理,但它就是那样存在和使用,所以对于每一个非明确确定的需求,要由专业人员来审定。除非你就是专家。

3.3. 改进

最初的第一次需求在分析,细化一定有不明及不确定之处,那么就把整理出一份问题细化问询表,对发现的问题进行整理,列出不明之处,可根椐以下格式

问询人:

问题:

业务不清问题列表(业务描述不清):

1 ….是什么含义?

2 …..与XX是什么关系?

多种选择可以列表(请用户进行选择):

1 ……有多个可能,那么现在我们使用

A ……   B…….   C……..  D ……

 

3.4. 审核需求

  1. 自我审枋 
    把自己从用户的角度来考虑 
    是否合理,是否可以提高效率,是否可以达到目的,是否有完整
  2. 由用户来评价 
    由最终用户来评价你所列的需求是否达到了用户要求(用户人数1-3人,再多也没有什么益处)。
  3. 重复过程,最终通过审核完成需求说明书

 

如何编写出好的用户需求文档

许多软件开发团队没有需求工程师;开发人员捕获、编写和管理所有的需求。这在资源效率方面是有意义的:开发人员可以在正式编码之前,在系统停机时间收集和编写需求。然而这一做法的缺点是,通常程序员没有在编写需求方面受过技术和工具的培训,结果他们总是费力和低效地工作,而且有时做出的需求规约不符合规范。

为了写出好的代码,开发人员必须知道很多事情:诸如控制结构和调用约定之类的基本概念;至少一门程序设计语言,包括它的语法和结构;操作系统基础;以及如何使用诸如编译器、调试器、集成环境这类的技术。好在他们能以所有这些知识为跳板写出好的需求来。通过应用许多与他们编写代码时相同的原则和概念,开发人员可以有效地担当起需求工程师的职责。

让我们看一些开发人员可以利用的编程概念。

遵循结构

所有的程序设计语言都有一种结构。这种结构指出程序的不同部分如何定义,彼此之间形成何种关系。Java程序由类来形成结构,COBOL程序有不同的“区段”,C程序有一个主程序以及多个子程序。

程序有一个特定的结构,需求也是如此。设想你把一个C程序的所有代码都塞到主程序里——它会变得不可读而且无法维护。与此相似,如果你的需求规约只是一张毫无规则的大列表,你也没办法使用它。不管你意识到没有,一组需求总有一个结构。获得需求中结构的最佳方法是把它们按不同类型来组织,而这些类型常常对应着不同的级别。

为理解不同类型之间的差别,我们来看看用于保险索赔处理的四条需求样例:

我们必须有能力处理积压下来的索赔单据。
系统必须能自动检查索赔表单以获得适用条款。
对索赔者,系统要根据其社会保险号码确定其是否是注册用户。
系统要支持处理多至100个并发的索赔请求。
你的直觉或许会告诉你其中每条需求都有一些不同的东西。第一条需求是级别很高的;它在表达业务需要的时候甚至没有提到系统本身。第二条需求表达了系统应该做什么,但仍在较高的级别上;它仍然太宽泛,不能直接翻译成代码。第三条是低级别的需求;它确实为软件必须完成的功能提供了足够的细节,使你能写成代码。第四条需求虽然非常详细,但并没有告诉你系统必须做什么;它只是规定了系统必须有多快。当你跟用户和其他涉众打交道时,这些需求是非常典型的。也许你已经看到为什么把它们放在一个大而无组织的表上会导致混乱。

为使需求更为可用,你可以把它们按范畴或类型分开,比如:

业务需要
特性
功能性软件需求
非功能性软件需求
这是IBM Rational Unified Process(RUP)中建议的类型。它们绝非唯一可能的类型,但它们表达了一种有用的方法。在你的项目的早期,就要决定用什么类型。这样,在你从涉众那里收集信息时,要确定他们描述的是何种需求类型,然后写成需求。

注意你可以用两种格式之一指定功能性软件需求:声明形式和用例形式。上述第三条需求是声明形式的;它是粗线条的,用了一个“要……”的句式。另一个形式是用例的,它也指定了系统应该做什么,级别足够低,能直接写成代码,不过它提供了更多的上下文,告诉用户和系统应该如何交互以执行一些有价值的东西。(关于用例的更多细节见下文。)在你着手收集项目需求之前,你应该确定哪一类功能型需求是你要用的,以后就不要改变。

用习惯保证质量

你知道写出好的代码和坏的代码都是可能的。有很多途径导致坏的代码,其中之一就是使用非常抽象的函数名和变量名,比如routineX48,PerformDataFunction,DoIt,HandleStuff,do_args_method。这样取名没有给这些方法和过程的功能提供任何有用的信息,迫使读者钻进代码里去搞清楚。另一个糟糕的做法是用单字母的变量名如i,j,k。你用一个简单的文本编辑器无法搜索到这些变量,其功能也不清晰。

当然,你也有很多途径写出坏的需求。可能最糟的错误是二义性。如果一条需求让两个人按两种方式解释,这条需求就有二义性。比如,这是一个从实际需求规约里抽出来的需求:

应用程序在多个并发用户访问时必须极其稳定,且不能牺牲速度。
多个和极其这样的词有多种解释,所以这一需求是有二义性的。事实上,为了获得清晰性,你必须把它表达成这样三条非常具体的需求:

系统故障的平均间隔时间不能大于每星期一次。
系统应支持1000个并发用户同时查询数据库,而不会发生拥塞或数据丢失。
系统的平均响应时间在多至1000个并发用户时应小于一秒。
质量需求还有更多的属性,详见IEEE的指南。 1

详细编写注释

风格良好的程序包含注释,这些注释为代码提供了额外的信息,解释这段代码在做什么或者它为什么用这种方法写。好的注释不解释代码怎样做某件事情——这一点代码本身显然已经说清楚了——而只提供必要的信息帮助用户、维护人员和复审人员理解代码做了什么,以此保证质量。类似地,需求也有属性——这是使需求更为可读和可用的信息。当你捕获需求时你也应该寻求属性信息。例如,一个重要的属性是来源:这条需求是从哪里来的?记下你的信息的来路将在你需要回溯以获得更多信息时节约大量时间。另一个属性是用户优先级。如果一个用户给你五十条需求,他也应该让你知道其中每一条跟其他相关的比起来重要度如何。这样在项目生存周期的后期,时间越来越紧迫,你意识到已经不可能满足所有的需求时,至少你还知道哪些是最重要的。

正如没有哪条规则告诉你代码里的注释一定要怎么写才正确,也不存在“正确”属性的一个普适的列表。来源和优先级几乎总是有用的,但你必须定义适合你的项目的其他属性。当你搜集需求时,试着预计一下当你着手设计系统和编码时整个团队可能需要什么信息。

熟悉语言

显然,开发人员必须熟悉他们用来编码的语言,不管是Java,COBOL,C++,C,Visual Basic,Fortran还是其他什么语言。为了写出好的代码,你必须了解语言之间的细微差别。虽然所有语言里基本的程序设计概念都是一样的,但在具体某个操作时它们会使用不同的方式。比如,Java的循环结构用“for”;Fortran则用“DO”。C语言里你以子程序名带上参数来调用一个子程序;Fortran里你用一个CALL语句。

为了写好需求你也得熟悉语言。多数需求是用自然语言写成的(法语、英语等等)。自然语言非常强大,但也非常复杂;未受过写作训练的开发人员在写作中表达复杂想法的时候有时会碰上困难。我们这里没有足够的篇幅留给一个完整的写作课程,但有些指导原则是有用的。

首先,对声明形式的需求使用完整的句子。(例如,以“应”或者类似的结构表达的语句。)在每个句子里检查主语和动词。

第二,使用简单句。一个语句只包含一个独立子句,只传达一个想法时,更易于理解、检验和测试。如果你的需求太复杂,难以用简单句表述,试着把它分解成几条更小、更易于定义的需求。并列句和复合句会引入依赖关系(分支);换言之,它们可能描述那些依赖某些动作的变量,结果常常产生一条不必要的复杂需求,增加测试的困难。

简单句:系统应能显示车沿跑道绕行一圈花费的时间。
并列句:系统应能显示车沿跑道绕行一圈花费的时间,且时间的格式应是hh:mm:ss。(这是两条需求,一条是功能性需求,指定系统要做什么,另一条是用户界面需求,指定时间格式。)
复合句:系统应能在车沿跑道绕行一圈后5秒之内显示这一圈花费的时间。(这也是两条需求,一条功能性需求和一条性能需求。)
为了给并列句和复合句写出合适的测试,你只能把其中的两条需求分开。既然如此为什么不干脆从一开始就这样做呢?以下是把上述复合句拆分成简单句的一种方案:

系统应能显示车沿跑道绕行一圈花费的时间。
绕行时间的显示格式应为hh:mm:ss。
绕行时间应在一圈结束后5秒内显示出来。
注意,为使需求更易测试,它们写得更易阅读。

还有一个写好需求的技巧:使用一致的文档格式。你已经有了一个编码的格式或模板。编写需求的时候也可以利用它。一致性是关键;每个规约文档应该用相同的标题、字体、缩进等等。模板有助于做到这点。实际上,它们起到表单的作用;编写需求的开发人员编写好的规约就无需从草稿开始,做重新发明车轮的工作。如果你需要模板的样例,RUP上面有很多。

需从草稿开始,做重新发明车轮的工作。如果你需要模板的样例,RUP上面有很多。

遵循指南

许多开发团队使用类似这样的编码指南:

将模块的定义和实现放在不同的文件里(C++)。
在一个代码块的范围内作缩进(Java)。
将频繁调用的数据元素放在每组工作存储区变量的开头(COBOL)。
在编写需求时你也应该遵循某种指南。例如,你如果决定用用例来规约软件需求,你的指南就应该告诉你如何写出事件流程。用例事件流程解释了系统和用户(参与者)如何通过交互完成工作。你的指南应当描述在主流程里发生什么(成功场景),在备用流程里发生什么(意外场景),也应该描述如何组织这些流程的结构。你的指南也应该提示两个流程的长度以及其中的独立步骤。如果你决定使用传统的声明式需求,则指南应当解释如何编写需求。好在许多这样的指南已经在RUP和其他相关的资源里有了, 所以你不必自己撰写。 2

理解操作环境

为开发好的代码,你必须熟悉那台运行你的系统的机器,也必须熟悉怎样使用其操作系统。如果是Windows,你必须熟悉MFC和.Net。如果是Linux,你必须熟悉UNIX系统调用。

为写出好的需求,你要理解的是操作人员而不是操作系统。你也必须理解用户而不是用户界面。Java开发人员考虑类路径;需求编写人员考虑通向类(或工作组)的正确途径。

需求捕获是一项以人为中心的工作。你不能虚构需求,只能从其他人那里获得需求。这对内向的开发人员来说或许是个挑战,但如果能正确地应用已有的技能,他们是能成功的。

用户常常不知道他们要的是什么,或者知道是什么却不知道怎么描述它。开发人员却拥有这样的能力来改善这一点:他们常常不得不破解编译器给出的费解和难懂的错误信息。比如,Java开发人员在写一个小应用程序时可能碰上这样的信息:

load: com.mindprod.mypackage.MyApplet.class can't be instantiated. 
java.lang.InstantiationException: com/mindprod/mypackage/MyApplet
这是什么意思呢?如果开发人员不确定,他会去检查代码,查询编译器的文档,甚至利用Google这样的搜索引擎,来弄清问题出在哪儿。最后他将发现,他写的小应用程序代码缺少缺省的构造函数。

如果你正在为一个天气预报系统收集需求,涉众之一告诉你系统应能“用标准的带小尾巴的箭头显示200平方英里的一块区域之上大气层不同高度的风速和风向”,你就需要深度挖掘一下。你可以要一个类似的系统给出的报告,求助于气象学的书籍,也可以请另一名涉众把要求描述得更精确一些。你应当继续研究,直到掌握足够多的细节来描述期望的功能。这样你就可以重述需求,使之清晰和无二义性,提供足够的细节以支持设计。

另一个捕获需求的技巧是避免问诱导性的问题。虽然你对用户的需要可能已经有了想法,但如果你把这些和盘托出,你恐怕无法获知整体上他们到底需要什么。反之,问一些开放性的问题如“你要让分开的数据怎样显示?”而不要问“你要不要把气压和温度合起来显示在一张图表里?”

遵循既定原则

设计和编写优秀程序的基本原则中,有信息隐藏、耦合和内聚。在编写需求中也有与之相应的原则。

信息隐藏

这个原则是说一段代码的使用者/调用者不能访问甚至不能获知数据的内部细节。所有对数据的访问与修改必须通过函数调用来完成。这样,你在改变内部数据结构时不会影响到调用它的外部程序。

对于需求这也是一个好的原则,特别是在用例表达的情形。如我们所说过的,用例具有事件流程。写得不好的用例常有塞满了数据定义的事件流程。考虑这个管理购买请求用例的基本事件流程:

基本事件流程:

系统显示所有未决的购买请求。
每个未决请求包含该请求的如下信息(限制为char型):
授权ID (仅内部使用)
PO #
引用ID
发布者帐户缩写名
经销商帐户名(前10个)
经销商帐号
购买原因码
请求购买量
请求日期
分配给内部
注释指针
经授权的管理员可以做以下几件事之一:1)批准 2)拒绝 3)取消 或 4)分配请求。他选择1)批准。
……如此等等直到所有步骤完成。
以上十五行里,十一行用来说明哪些数据与一个未决请求在一起处理。这些信息很重要,但却使用例中发生的事情变得不清晰。更好的解决方案是将数据隐至别处。这些步骤就变成这样:

基本事件流程:

系统显示所有未决的请求。
经授权的管理员可以做以下几件事之一:1)批准 2)拒绝 3)取消 或 4)分配请求。他选择1)批准。
……如此等等直到所有步骤完成。
未决的购买请求用了斜体,指出数据在别处定义(通常在用例的特殊需求段或在词汇表中定义)。这使表达真实功能性需求的事件流程易于阅读和理解。

耦合与内聚

对编码人员,耦合原则是指程序中的单独模块应当尽可能地互不相关。 一个模块内部的处理应与其他模块的内部机制无关。内聚原则是指一个模块内部的所有代码应该只完成一个目标。这些原则使程序易于理解和维护。

这些原则对需求同样适用,尤其是用例。用例应当独立(即极少或没有耦合)。 3 每个用例应指定一个有意义的功能块,说明系统如何为参与者提供有价值的东西。参与者焦点很重要,你可以指定系统为参与者做什么,而不必担心用例按序排列的问题。

一个用例中所有的功能性成分应当只用于完成参与者的一个目标(高度内聚)。在一个典型的自动取款机(ATM)系统中,一个用例是“取款”,另一个是“转帐”。每个用例集中于单一的目标。如果你把这些功能合并到一个用例里,就成为低内聚的(和不合适的)依赖关系。

然而要小心,许多用例的初学者走过了头,建立了太多的低层用例。我看到过一个用于银行债务收集系统的模型,它拥有150个用例,用例的起名诸如“修改数据”。这个项目有一个十人团队,计划持续了差不多一年。然而,由于这些用例太琐碎,整个团队在推进的时候碰上了无数的麻烦。他们大量描述了对用户毫无价值的底层功能,这些功能既难以理解也难以使用。每个用例极为内聚,但也因此造成用例间的高度耦合。把层次提升到更明确的活动如“收集债务信息”,就能在耦合和内聚之间保持合适的平衡。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值