面向对象软件的实现与测试课件.ppt

上传人:牧羊曲112 文档编号:4068086 上传时间:2023-04-03 格式:PPT 页数:71 大小:307KB
返回 下载 相关 举报
面向对象软件的实现与测试课件.ppt_第1页
第1页 / 共71页
面向对象软件的实现与测试课件.ppt_第2页
第2页 / 共71页
面向对象软件的实现与测试课件.ppt_第3页
第3页 / 共71页
面向对象软件的实现与测试课件.ppt_第4页
第4页 / 共71页
面向对象软件的实现与测试课件.ppt_第5页
第5页 / 共71页
点击查看更多>>
资源描述

《面向对象软件的实现与测试课件.ppt》由会员分享,可在线阅读,更多相关《面向对象软件的实现与测试课件.ppt(71页珍藏版)》请在三一办公上搜索。

1、软 件 工 程,1,第八章 面向对象软件的实现与测试,8.1 类级关系8.2 类的实现8.3 应用的实现 8.4 测试一个面向对象的应用,软 件 工 程,2,在开发过程中,类的实现是核心问题。在只用面向对象风格所写的系统中,所有的数据都被封装在类的实例中而整个应用则被封装在一个更高级的类中。,软 件 工 程,3,8.1 类级关系,当实现类的时候就会遇到类级的关系。一个类的实现常常在某些方面依赖于其它类的实例。类级关系可以是应用级关系的实现,也可以是类内属性的实现。消息 组装 继承,软 件 工 程,4,1.消息(messaging),在应用程序中,应用级关系大多是以类的实例之间的消息连接方式实现

2、通信的。在消息的参数表中指定消息的接受者(一个类的实例)。还可以通过参数表向接收者提供信息。消息指定一个属于接收者的服务,这个服务应实现该类共有界面规定的行为。看Dictionary类设计的例子,软 件 工 程,5,一个Dictionary是包含一些可按关键码的值排序和检索对象的部件。对于存储在Dictionary内的一个实例来说,类必须提供一个操作来取得关键码。,Dictionaryprivate:contents a HashTablepublic:add(anItem),词典私有域 散列表共有域 方法add,软 件 工 程,6,关系 refers to 表示了“一个类引用另一个类”,后者

3、的实例可当作参数在前者发送的消息中使用。由消息构成的流图形成了面向对象系统结构的核心。,软 件 工 程,7,例如,Dictionary类有一个操作add,该操作将把一个属于Item类的对象item当作参数,把这个对象加入到Dictionary的一个对象中。具体地,add操作首先发送一个消息给做为参数的对象item,再利用它的关键码,到该对象所在的Item类中引用(refers to)相应的实例,把它加入到词典中去。在设计阶段,在两个类之间建立消息连接要求协调这些类的共有界面的定义。,软 件 工 程,8,2.组装(Composition),组装关系是一个实现级关系,它对应于应用级的聚合关系。它也

4、叫做component(构件)或叫做 is part of(是的一部分)。组装与消息两者都是类间的关系,在这种关系中,一个类的实例将是另一个类的实现的一部分。考虑Dictionary类的实现。,软 件 工 程,9,在Dictionary中存储item的一种数据表示是使用散列表(HashTable)。进行Dictionary类的低层设计时,要指明在Dictionary类和HashTable类之间的一个 is part of 关系。在实现时,应当在Dictionary类的定义中声明这个Hash Table的实例。,软 件 工 程,10,3.继承(Inheritance),继承允许在既存类的基础上定

5、义新类。一个新类 B 继承了既存类 A,则 B 包括了 A 定义的某些行为,以及它自定义的某些附加行为。有多少种面向对象程序设计语言,就有多少种不同的继承实现方式。,软 件 工 程,11,继承图,软 件 工 程,12,(1)针对实现的继承,两个类之间“针对实现”的继承关系的建立指的是使用既存类的内部表示来做为新类的内部表示的一部分。我们不推荐这种继承方式。考虑使用继承来实现一个Circle类,为了定义一个圆,需要定义一个点和一个值,做为圆的圆心和半径。因此,Point类可支持Circle类的一部分实现。把Point类当做派生类。,软 件 工 程,13,如果Circle类直接使用Point类的数

6、据成员x和y,将失去抽象。而且失去做为一个点的圆心的标识。针对实现的继承一般在原型开发中使用。,软 件 工 程,14,(2)针对特殊化的继承,这种继承的使用适合于大多数面向对象程序设计语言所提供的关系,是针对一般化-特殊化关系的。is a 继承关系类B 的一个实例是类A 的一个实例。在使用中,既存类的界面可成为新类的界面。这表明新类具有它的基类的所有行为。,软 件 工 程,15,软 件 工 程,16,is kind of 继承关系这种继承允许有选择地包含既存类的属性,从而建立新的定义。一个鸟类可能有一个关于飞行的属性。一个鸵鸟派生类在模型化时可能就不选择这个属性,因为鸵鸟不会飞。鸵鸟是一种鸟,

7、但具有的属性与鸟不完全相同。is kind of 继承是不严格继承。,软 件 工 程,17,8.2 类的实现,一种方案是先开发一个比较小的比较简单的类,做为开发比较大的比较复杂的类的基础。即从简单到复杂的开发方案。在这种方案中,类的开发是分层的。一个类建立在一些既存的类的基础上,而这些既存的类又是建立在其它既存的类的基础上。通过诸如“is a”或“is part of”之类的关系,利用既存代码就能着手建立新的类。,软 件 工 程,18,1.软件库(Software Base),建立软件库的目的是为了引用现成的构件。存储在软件库中的类以多种途径发生关联,同时,库可以追踪这些关联。软件库工具利用这

8、些关联可以有效地进行开发。,软 件 工 程,19,2.复用(Reuse),伴随着类的设计,应当从复用开始着手类的实现。类的设计可以使用各种抽象的类。在类设计期间,还需要建立这些类中的“具体的”对象。一旦一个数据对象被确认是应用所需要的,则必须把它组织成类,以便有效地提交所需要的模型。,软 件 工 程,20,产生所需功能的次序,寻找可“原封不动(As_is)”使用的现成的类,提供所需要的特性;寻找可以用做开发新类的基础的现成的类,通过继承演化出新的类;不用任何复用,开发一个新类。,软 件 工 程,21,3.断言(Asserttions),实现类的一个主动方法是把来自类的设计信息直接纳入代码。特别

9、要求把参数约束、循环执行等编入到代码中。这可以通过某些表示断言的语言机制来实现。一个断言就是一个语句,它表达了对一个过程、一个值,甚至一段代码的约束。,软 件 工 程,22,在栈的描述中,可以使用断言来控制进栈和退栈功能的操作:procedure push(var S:Stack_Type;New_Item:Item_Type);assert:The stack S is not full/precondition assert:The top of stack S contains New_Item/postconditionend;,软 件 工 程,23,procedure pop(var

10、 S:Stack_Type)return Item_Type;assert:The stack S is not empty/precondition assert:The stack S has one fewer items that it did on entry/postconditionend;前置条件 precondition 后置条件 postcondition,软 件 工 程,24,在C与C+中有一种头文件:“assert.h”,它支持断言的格式。例如,实现者可以针对pop操作,作出断言如下:assert(TOP0)这样,宏就会检查在试图从栈中退出一项之前栈是否空。如果条件测试

11、失败,则会打印出一条消息,报告源文件名及在文件中发生失效的行号。,软 件 工 程,25,4.调试(Debugging),数据封装限定了许多用以修改数据值的手段,也限定了对错误的数据值进行调查以找出真正原因的功能。某些面向对象的程序设计环境支持使用交互工具进行调试。工具包括断点的设置、访问源代码、检查对象(包括修改数据值和表达式求值)及编辑源代码。,软 件 工 程,26,5.错误处理(Error Handling),我们期望一个类能够自负错误处理的责任。类的实例负责定位和报告错误。在错误处理中使用状态码方法。各种不同的状态码的值能够指明任务的执行是成功还是失败,若是失败又是哪种程度的失败。例如,

12、中函数“fopen”返回的状态码。如果打开失败,则返回零值;如果打开成功,则返回文件的标志。,软 件 工 程,27,使用状态码方法的难点在于:各个程序必须知道它所调用函数的状态码,并能检验这些状态码及采用行动。如果问题的解决在比它发生的那一层更高的一层进行处理,这将产生比预想更高程度的耦合。因此,问题尽可能在它发生的那一层进行处理。例如,在fopen打开文件失败时,如果当前的文件名不存在,软件可以要求用户键入另一个文件名。,软 件 工 程,28,6.内建错误处理(Built_In Error Handling),Ada程序员可以利用语言所提供的例外处理机制帮助做错误处理。一个“例外”是做了意料

13、之外的事情的处理。“例外处理器”是一段代码,在一个特定的例外出现时调用。它可以是 终止软件的执行;发信号给一个更高层的例外处理器;对问题进行定位处理。,软 件 工 程,29,7.用户定义的错误处理(User_Defined Error Handling),有两种相对简单的错误处理技术,它们提供了打印出错信息和终止软件执行的能力。它们都不允许嵌套的错误处理。第一种技术使用了一个全局错误处理器对象。每一个类都能对这个全局对象进行存取。,软 件 工 程,30,当在一个用户对象中检测出一个错误的时候,就发送一个消息给这个全局对象。这个消息运载了一个字符串,它就是要被打印的出错信息,消息中还有一个整数,

14、它指出错误的严重程度。消息格式为:ERROR_HANDLER.handle(Message to be printed,1);ERROR_HANDLER将打印消息并终止应用的执行。,软 件 工 程,31,第二种用户定义错误处理的技术要求每个类都定义或再定义一个命名为error的操作。这个操作不应是类的共有界面部分,它应是一个隐蔽的实现部分,可以被一些公共操作调用以检测错误。这种error操作可以打印消息,在适当时候请求一些额外输入,在必要时终止软件的执行。,软 件 工 程,32,8.多重实现(Multiple Implementation),同一个类可以多种方式实现。为此,软件库必须对库中的每

15、一部分都能保留充足的信息,使得定义能同时关联到不止一个实现。为了定义连接到几个实现所使用的关系。程序员应能指出要求的实例所在的类,并确定所期待的特定实现。,软 件 工 程,33,stack类的界面,关系,是的实现,基于数组的栈,基于链表的栈,软 件 工 程,34,8.3 应用的实现,应用的实现是在所有的类都被实现之后的事情。实际上,当把类开发出来时就已经实现了应用。每个类提供了完成应用所需要的某种功能。在C+和C中有一个 main()函数。可以使用这个过程来说明构成应用的主要对象的那些类的实例。,软 件 工 程,35,C+系统中主过程的两个主要职责是 建立实例;通过指针建立对象之间的通信;以图

16、形系统为例,首先建立一个用户界面的单一实例。一旦它建立起来,就发送一个消息,启动绘图程序的命令循环。然后,这个对象担负起在系统寿命的其余时期协调通信关系和对象建立的责任。,软 件 工 程,36,对于纯面向对象的语言,在系统中的每个“事物”都是对象。在这些语言中没有“主过程”。用户建立起一个类的实例,然后,通过实例接受控制和执行服务,产生实例输出的结果或接收由用户发送来的消息。由那些原始消息而产生的消息序列就成为目标软件的功能。,软 件 工 程,37,8.4 面向对象测试,面向对象系统的测试与传统的基于功能的系统的测试之间存在很大差别:对象作为一个单独的构件一般比一个功能模块大。由对象到子系统的

17、集成通常是松散耦合的,没有一个明显的“顶层”。如果对象被复用,测试者无权进入构件内部来分析其代码。,软 件 工 程,38,面向对象系统的测试可分为4个层次:测试与对象相关联的单个操作 它们是一些函数或程序,传统的白盒测试和黑盒测试方法都可以使用。测试单个对象类 黑盒测试的原理不变,但等价划分的概念要扩展以适合操作序列的情况。测试对象簇(聚集)严格的自顶向下或自底向上的集成不适合一组关联对象的情形。应使用基于场景的测试等其他方法。,软 件 工 程,39,对象类测试,测试面向对象系统 根据系统需求规格说明进行检验和有效性验证的过程可以像对其他范型的系统一样进行。,在测试对象时,完全的覆盖测试应当包

18、括:隔离对象中所有操作,进行独立测试。测试对象中所有属性的设置和访问。测试对象的所有可能的状态转换。所有可能引起状态改变的事件都要模拟到。,软 件 工 程,40,对象类,作为在语法上独立的构件,应当允许在不同应用中使用。每个类都应是可靠的且不需了解任何实现细节就能复用。因此对象类应尽可能孤立地进行测试。设计操作的测试用例时的要点:首先定义测试对象各操作的测试用例。对于一个单独的操作,可通过该操作的前置条件选择测试用例,产生输出,让测试者能够判断后置条件是否能够得到满足。,软 件 工 程,41,各个操作的测试与传统对函数过程定义的测试基本相同。然后再把测试用例组扩充,针对被测操作调用对象类中其他

19、操作的情况,设计操作序列的测试用例组。测试可以覆盖每个操作的整个输入域。但这不够,还必须测试这些操作的相互作用,才能认为测试是充分的。各个操作间的相互作用包括类内通信和类间通信。,软 件 工 程,42,软 件 工 程,43,设计对象类的规格说明测试时的要点:把对象类当做一个黑盒,确认类的实现是否遵照它的定义。对于“栈”的测试应当确保 LIFO 原则得以实施。对于多数的对象类,主要检验在类声明的 public 域中的那些操作。对于子类,要检查继承父类的public 域和protected 域的那些操作。检查所有public域,protected域及private 域中的操作以完全检查对象中定义的

20、操作。,软 件 工 程,44,等价划分的思想也可用到对象类上。将使用对象相同属性的测试归入同一个等价划分集合中。这样可以建立对对象类属性进行初始化、访问、更新等的等价划分。在设计对象类的行为测试时需要注意:基于对象的状态模型进行测试时,首先要识别需要测试的状态的变迁序列,并定义事件序列来强制执行这些变迁。原则上应当测试每一个状态变迁序列,当然这样做测试成本很高。,软 件 工 程,45,对象集成测试,当开发面向对象系统时,集成的层次并不明显。当一组对象类通过组合行为提供一组服务时,则需将它们一起测试,这就是簇测试。此时不存在自底向上和自顶向下的集成。,完全的单元应当保证类的执行必须覆盖它的一个有

21、代表性的状态集合。构造函数和消息序列(线程)的参数值的选择应当满足这个规则。,软 件 工 程,46,对象集成测试又称交互测试,目的是确保对象的消息传递能够正确进行。面向对象系统的集成测试有3种可用的方法:用例或基于场景的测试 用例或场景描述了对系统的使用模式。测试可以根据场景描述和对象簇来制定。这种测试着眼于系统结构,首先测试几乎不使用服务器类的独立类,再测试那些使用了独立类的下一层次的(依赖)类。这样一层一层地持续下去,直到整个系统构造完成。,软 件 工 程,47,基于线程的测试 它把为响应某一系统输入或事件所需的一组对象类组装在一起。每一条线程将分别测试和组装。因为面向对象系统通常是事件驱

22、动的,因此这是一个特别合适的测试形式。对象交互测试 这个方法提出了集成测试的中间层概念。中间层给出叫做“方法-消息”路径的对象交互序列。所谓“原子系统功能”就是指一些输入事件加上一条“方法-消息”路径,终止于一个输出事件。,软 件 工 程,48,子类测试 在做继承层次的测试时,自顶向下测试比较容易,但如何测试有几种看法:Fielder认为在父类充分测试的基础上,被子类继承的方法只需最小测试。Horrold主张在测试子类时,只需对被继承的属性和新的属性之间的交互进行测试。D.E.Perry和G.E.Kaiser以Weyuker的测试充分性公理为依据,认为子类中继承的方法和重新定义的方法都必须在子

23、类环境中重新测试。,软 件 工 程,49,面向对象的确认测试,在确认测试或系统测试的层次上,不再考虑对象类间相互连接的细节。主要着眼于用户可见的动作和用户可识别的系统输出。为了帮助确认测试的执行,测试者需要回到分析时的动态模型和描述系统行为的事件序列(脚本)进行测试。可以利用黑盒测试的方法来驱动确认测试。测试检测软件中的故障并确定软件是否执行了预定要开发的功能。,软 件 工 程,50,面向对象测试用例的设计,测试过程包括了一组测试用例的开发,每一个测试用例要求能检验应用的一个特定的元素。还需要分析用各个测试用例执行测试的结果来收集有关软件的信息。软件测试人员可以参考以下方法:应当唯一标识每一个

24、测试用例,并与被测试的类显式地建立关联。陈述测试对象的一组特定状态。,软 件 工 程,51,对每一个测试建立一组测试步骤,要思考和确定的问题包括:被测试对象的一组特定状态;一组消息和操作;考虑在对象测试时可能产生的一组异常;一组外部条件;辅助理解和实现测试时的补充信息。传统的白盒测试方法可用在类定义的操作测试和类级别测试中,黑盒测试方法可用于多类测试。,软 件 工 程,52,分布式系统的测试,分布式处理中涉及的最基本单位是线程,线程是操作系统进程内部能够独立运行的内容,它拥有自己的程序计数器和本地数据。线程是能够被调度执行的最小单位。分布式系统测试主要面临的问题是并发性、网络化和分布式。并发性

25、是指多个线程同时发生。针对并发性错误的测试主要着重于两个线程的交互。在实际实施交互机制前应对相关方法进行测试。,软 件 工 程,53,在网络环境中各个独立的盒子连接到通信设施上,如何实现它们物理上的同步是网络计算的问题。相关的测试就是在组成一个网络系统的各个自治机器之间同步问题的测试。分布式系统使用多进程来支持系统的灵活性一个对象既可以在同一台机器上分布在多个进程中,还可以分布在多个物理上的计算机上。所有这些分布式构件都要能够识别“命名服务”或“注册”对象,能够与其他构件交互。所有在配置文件中登记的机器与构件构成基础结构。,软 件 工 程,54,需要考虑与这些分布式构件相关的测试。分布式系统中

26、的路径测试一条路径是一系列逻辑上连续的语句,它只有在特定的输入下才执行。路径的另一个定义是覆盖变量的定义和使用就形成一条完整的路径。路径测试就是设计测试用例覆盖一个同步顺序。所谓同步顺序是指同步事件按照特定次序发生的顺序,而同步事件是指一个线程产生另一个线程。,软 件 工 程,55,测试应跟踪一个事件到另一个事件的路径。如果从一个同步事件到另一个同步事件有多条可能的控制流路径,只需覆盖其中一条路径。生存周期测试在分布式系统中,生存周期测试是指选择一系列测试用例,测试任何处于生存期中的对象。特别是在整个生存周期过程中存在多条路径,测试必须选择有代表性的路径以保证最大的覆盖范围。,软 件 工 程,

27、56,对于一个类来说,生存周期意味着选择一系列测试,每个测试构造类的一个实例,并通过一系列消息来使用实例,最后再撤销这个实例。一个有效的生存周期测试应能证实对象本身是否正确,还应能证实被测试项是否能够与它所在的环境正确地交互。对于一个类的实例,在它被撤销后必须检查它占用的资源是否已被释放掉。,软 件 工 程,57,分布式模型,下面讨论用在分布式系统中的使用某些标准基础结构的测试过程。基本的客户机服务器模型客户机服务器模型是最简单的分布式模型。在这种模型下,多个客户机都可访问服务器。服务器是单一进程。由于所有客户机都与同一个服务器交互,因此存在单点失败(即服务器出现问题将影响所有客户机)。测试要

28、点:,软 件 工 程,58,在延时期间,面对同时收到的服务请求,服务器能否把正确结果发送给各个相应的客户机?服务器能否处理快速增长的负载?当负载增加时,服务器的性能可能降低,因此可能选择放弃一部分负载。标准分布式模型 CORBACORBA是对象管理组织OMG开发的公共对象请求代理体系结构,并将它作为分布对象系统的标准体系结构。,软 件 工 程,59,这种结构的核心是对象请求代理(ORB),一个对象通过ORB与系统中的另一个对象通信。CORBA标准的特点:与基础结构相联系的机器可能有不同的操作系统和不同的存储设计;构成分布式系统的构件可以用不同的语言编写;根据对象的分布性和网络中机器的类型,基础

29、结构可以改变它自身的配置。测试要点:,软 件 工 程,60,不考虑基础结构的配置,系统能够正确的工作?测试用例应能产生被测试基础结构的各种预期的配置。在标准基础结构的服务基础上,构造新的测试用例能否被重复使用?测试用例的设计应尽可能地使用基础结构。新发布的特定基础结构能否与已有的应有有效地结合起来?应有一系列的回归测试,使得新发布的基础结构能够在被集成到产品中之前得到测试。,软 件 工 程,61,标准分布式模型 DCOMDCOM是 Microsoft 开发并鼓励的一种标准的分布式构件对象模型。DCOM“标准”被描述为包含特定方法的标准接口,每个标准接口都提供了一套特定的服务。单个构件可以完成几

30、个接口的服务,或若干构件中的每一个都能完成统一接口的服务,只是方式不同。DCOM是低层次的技术,支持构件间最原始的联系,它不作为应用开发的部分。,软 件 工 程,62,测试要点:对各种构件做任意配置时测试者能否正确编排唯一的标识?测试用例应能利用各种构件确保所有必要的连接能够成功。每个构件能否实现必要的接口?测试用例应能利用各种构件确保所有服务是可利用的并能实现期望的功能。标准接口的实现能否提供正确的行为?应针对每一种标准接口有一套测试。标准分布式模型 RMI,软 件 工 程,63,RMI是Java中的远程方法调用包,它提供一种简化的分布式环境,该环境假定不论连接的是什么样的或什么类型的机器,

31、它们都能运行Java虚拟机。RMI提供一个注册对象,参与分布式系统的所有对象必须知道该注册对象监听到哪个端口的消息。RMI的最新版本使用ORB的Internet协议(IIOP),使RMI对象与CORBA对象共同工作。,软 件 工 程,64,测试要点:那些种CORBA测试模式能够在以RMI为基础的系统上使用?测试用例的构造很多与CORBA的测试用例相同。一般分布式构件模型分布式系统的基本体系如图,主要活动是服务请求方给服务提供方法送消息。请求首先发送给请求方本地的代理对象,代理方联系通信基础结构并传送请求,通信基础结构实例化服务提供方,从对象定,软 件 工 程,65,位器的服务中获得服务提供方的

32、引用,并将服务请求传递给它。如果存在结果,则结果沿原路径返回。由于请求代理方可以引导请求,所以提供方不知道分布的细节。,软 件 工 程,66,用于提供方构件的测试的要点:根据规范准备测试用例。ProviderTest类应包括相应测试驱动程序,该类继承自GenericModelTester。设计基于说明的测试用例:对提供方可提供的一系列基于分布式系统的服务设计测试用例,放在GenericModelTester类中,对基于特殊应用服务设计的测试用例则放在ProviderTest类中。设计基于实现的测试用例:满足路径或代码覆盖的范围标准。,软 件 工 程,67,设计交互式测试用例:提供方应与请求服务

33、且具有代表性的请求方交互。每个主要的协议都应得到测试,且至少有一个请求方参与到这个协议中来。设计基于状态的测试用例:当请求方发出请求时,提供方可能只处于一种状态。但它可能同时从多个请求方接收请求,因此应使用所有必要的协议,使提供方经历所有可能的状态。用于请求方构件的测试的要点:,软 件 工 程,68,根据规范准备测试用例。RequesterTest类应包括相应测试驱动程序。在这个类中应提供用于执行功能性、结构性和交互性测试用例的操作。测试类在应用程序中可当作交互类使用。设计基于说明的测试用例:在API文档中构造每个方法的前置条件和后置条件。执行用于每个方法中每个后置条件中所有语句的测试用例。设

34、计基于实现的测试用例:满足一般的范围标准。,软 件 工 程,69,设计交互式测试用例:重点放在请求方与每个提供方之间的完整协议。为使得计时效果较为明显,应适当插入人为延时。设计基于状态的测试用例:请求方有一系列与它自己的分布相关的状态,如与基础结构相连或撤销连接等。测试应包括一系列经历所有这些状态的测试用例,还应包含与应用语义学相关的一些状态。最大的分布式系统 Internet测试因特网上可以连接、增加或删除服务器。,软 件 工 程,70,这类测试重点在Web服务器上和因特网应用程序的生存周期上。Web服务器测试Web服务器体系结构如图所示。Web页面和浏览器、应用服务器协作产生应用。,软 件 工 程,71,这些系统使得用户服务自动化:页面接受输入,并放入一个用户订购表中。然后产生一条顾客记录,调用能够自动产生一个账号和密码的应用程序。最后把账号信息通过Email发送给用户。测试涉及两方面。首先,执行脚本看它所做的工作是否是其所期望做的?其次,检查应用程序和网页所期待的当前数据是否正确。是否是所期望的格式?因特网应用程序生存周期的测试跨越不同平台的一系列用户事务测试。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号