-
NUnit详细用法(转至wyscorpion)
2007-01-04 00:38:18
前一段时间,有人问我在.NET里如何进行TDD开发.这个问题促使我想对NUnit做一个详细的介绍.因为我们大家都知道NUnit是在.NET进行TDD的利器.如果你已经知道很多关于NUnit的应用,请指出我的不对之处和提出一些建议,使本文更加完善.如果你对NUnit还不是很了解的话,我建议你还是阅读一下.本文分为以下部分:1. TDD的简介
首先什么是TDD呢?Kent Beck在他的<<测试驱动开发 >>(Addison-Wesley Professional,2003)一书中,使用下面2个原则来定义TDD:· 除非你有一个失败的自动测试,永远不要写一单行代码.· 阻止重复我想第一个原则是显而易见的.在没有失败的自动测试下就不要写代码.因为测试是嵌入在代码必须满足的需求中.如果没有需求,就没有必要实现任何东西.所以这个原则阻止我们去实现那些没有测试和在解决方案中不需要的功能.第二个原则说明了在一个程序中,不应该包含重复的代码.如果代码重复,我想这就是不好的软件设计的象征.随着时间的流逝,它会对程序造成不一致的问题,并且使代码变非常混乱 ,因为我们时常不会记得重复代码的位置.如果发现代码重复,我想我们应该立即删除代码重复.其实这就涉及到重构了.在这里我就不多讲了.一般来说,测试分为2种类型,一是程序员自己的测试,另外一种是客户的测试.关于客户测试,我推荐一个FIT的框架,非常不错。在这里,我们讲的TDD就是程序员测试.那么什么是程序员测试呢?我认为就是我们常说的单元测试.既然是单元测试,在.NET里势必会用到某些工具,目前最著名恐怕就是我即将介绍的NUnit了,2.NUnit的介绍
NUnit是一个单元测试框架,专门针对于.NET来写的.其实在前面有JUnit(Java),CPPUnit(C++),他们都是xUnit的一员.最初,它是从JUnit而来.现在的版本是2.2.接下来我所用的都是基于这个版本.NUnit最初是由James W. Newkirk, Alexei A. Vorontsov 和Philip A. Craig, 后来开发团队逐渐庞大起来.在开发过程中, Kent Beck 和Erich Gamma2位牛人也提供了许多帮助.看来对于NUnit还真是下了一番力气了.JNUnit是xUnit家族种的第4个主打产品,完全由C#语言来编写,并且编写时充分利用了许多.NET的特性,比如反射,客户属性等等.最重要的一点是它适合于所有.NET语言.如果你还没有下载,可以到http://www.nunit.org/去下载.2.1 NUnit的介绍
Ok,下面正式讲解NUnit.在讲解之前,看看几张图片:图1 NUnit运行的效果
图2 NUnit运行的另外一个效果从中我们可以非常容易发现,右边是个状态条,图1是红色的,图2是绿色的.为什么会这样呢?因为如果所有测试案例运行成功,就为绿色,反之如果有一个不成功,则为红色,但也有黄色的.左面的工作域内则是我们写的每一个单元测试.通过上面的图片,我想你对NUnit有个总的了解了.接下来还是分为2个部分,一是NUnit的布局,另外一部分就是它的核心概念.首先熟悉一下NUnit GUI的布局.让我们更进一步看一下测试运行器窗口的布局。在右边面板的中间,可以看到测试进度条。进度条的颜色反映了测试执行的状态:绿色 描述目前所执行的测试都通过黄色 意味某些测试忽略,但是这里没有失败红色 表示有失败底部的状态条表示下面的状态:状态.说明了现在运行测试的状态。当所有测试完成时,状态变为Completed.运行测试中,状态是Running: <test-name> (<test-name>是正在运行的测试名称)。Test Cases说明加载的程序集中测试案例的总个数。这也是测试树里叶子节点的个数。Tests Run 已经完成的测试个数。Failures 到目前为止,所有测试中失败的个数.Time 显示运行测试时间(以秒计)File主菜单有以下内容:New Project允许你创建一个新工程。工程是一个测试程序集的集合。这种机制让你组织多个测试程序集,并把他们作为一个组对待。Open 加载一个新的测试程序集,或一个以前保存的NUnit工程文件。Close关闭现在加载的测试程序集或现在加载的NUnit工程。Save 保存现在的Nunit工程到一个文件。如果正工作单个程序集,本菜单项允许你创建一个新的NUnit工程,并把它保存在文件里。Save As允许你将现有NUnit工程作为一个文件保存。Reload 强制重载现有测试程序集或NUnit工程。NUnit-Gui自动监测现加载的测试程序集的变化。当程序集变化时,测试运行器重新加载测试程序集。(当测试正运行时,现在加载的测试程序集不会重新加载。在测试运行之间测试程序集仅可以重新加载。一个忠告:如果测试程序集依赖另外一个程序集,测试运行器不会观察任何依赖的程序集。对测试运行器来说,强制一个重载使全部依赖的程序集变化可见。Recent Files 说明5个最近在NUnit中加载的测试程序集或NUnit工程(这个列表在Windows注册表,由每个用户维护,因此如果你共享你的PC,你仅看到你的测试)。最近程序集的数量可以使用Options菜单项修改,可以访问Tool主菜单。Exit退出。View菜单有以下内容:Expand一层层扩展现在树中所选节点Collapse 折叠现在树中选择的节点Expand All递归扩展树中所选节点后的所有节点Collapse All递归折叠树中所选节点后的所有节点Expand Fixtures扩展树中所有代表测试fixture的节点。Collapse Fixtures 折叠树中所有代表测试fixture的节点。Properties 显示树中现所选节点的属性。Tools 菜单由这些项:Save Results as XML作为一XML文件保存运行测试的结果。Options让你定制NUnit的行为。现在看看右边,你已经熟悉Run按钮和进度条。这里还有一个紧跟Run按钮的Stop按钮:点击这个按钮会终止执行正运行的测试。进度条下面是一个文本窗口,在它上方,由以下4个标签:Errors and Failures 窗口显示失败的测试。在我们的例子里,这个窗口是空。Tests Not Run 窗口显示没有得到执行的测试。Console.Error 窗口显示运行测试产生的错误消息。这些此消息是应用程序代码使用Console.Error输出流可以输出的。Console.Out窗口显示运行测试打印到Console.Error输出流的文本消息。2.2 一些常用属性
接下来,我将讲述这个框架如何使用.同时也涉及到一些非常重要的概念,我想其客户属性是非常重要的.在NUnit里,有以下几种属性:- Test Fixture
- Test
下面我将对每种属性一一讲解.TestFixtureAttribute
本属性标记一个类包含测试,当然setup和teardown方法可有可无.(关于setup 和teardown方法在后面介绍)做为一个测试的类,这个类还有一些限制- 必须是Public,否则NUnit看不到它的存在.
- 它必须有一个缺省的构造函数,否则是NUnit不会构造它.
- 构造函数应该没有任何副作用,因为NUnit在运行时经常会构造这个类多次,如果要是构造函数要什么副作用的话,那不是乱了.
举个例子1 using System;
2 using NUnit.Framework;
3 namespace MyTest.Tests
4{
5
6 [TestFixture]
7 public class PriceFixture
8 {
9 //
10 }
11}
12TestAttribute
Test属性用来标记一个类(已经标记为TestFixture)的某个方法是可以测试的.为了和先前的版本向后兼容,头4个字符(“test”)忽略大小写.(参看http://nunit.org/test.html)这个测试方法可以定义为:public void MethodName()从上面可以看出,这个方法没有任何参数,其实测试方法必须没有参数.如果我们定义方法不对的话,这个方法不会出现在测试方法列表中.也就是说在NUnit的界面左边的工作域内,看不到这个方法.还有一点就是这个方法不返回任何参数,并且必须为Public.例如:1using System;
2using NUnit.Framework;
3
4namespace MyTest.Tests
5{
6 [TestFixture]
7 public class SuccessTests
8 {
9 [Test] public void Test1()
10 { /**//* */ }
11 }
12}
13
14一般来说,有了上面两个属性,你可以做基本的事情了.
另外,我们再对如何进行比较做一个描述。
在NUnit中,用Assert(断言)进行比较,Assert是一个类,它包括以下方法:AreEqual,AreSame,Equals, Fail,Ignore,IsFalse,IsNotNull,具体请参看NUnit的文档。
3.如何在.NET中应用NUnit
我将举个例子,一步一步演示如何去使用NUnit.第1步.为测试代码创建一个Visual Studio工程。
在Microsoft Visual Studio .NET中,让我们开始创建一个新的工程。选择Visual C#工程作为工程类型,Class Library作为模板。将工程命名为NUnitQuickStart.图4-1是一个描述本步骤的Visual Studio .NET。
图 4-1: 创建第一个NUnit工程第2步.增加一个NUnit框架引用
在Microsoft Visual Studio .NET里创建这个例子时,你需要增加一个nunit.framework.dll引用,如下:在Solution Explorer右击引用,然后选择增加引用nunit.framework组件,在Add Reference对话框中按Select和OK按钮。图4-2 描述了这步:
图 4-2: 增加一个 nunit.framework.dll 引用到工程第3步.为工程加一个类.
为工程加一个NumbersFixture类。这里是这个例子的代码。1using System;
2using NUnit.Framework;
3
4namespace NUnitQuickStart
5{
6 [TestFixture]
7 public class NumersFixture
8 {
9 [Test]
10 public void AddTwoNumbers()
11 {
12 int a=1;
13 int b=2;
14 int sum=a+b;
15 Assert.AreEqual(sum,3);
16 }
17 }
18}
19第4步.建立你的Visual Studio 工程,使用NUnit-Gui测试
从程序->NUnit2.2打开NUnit-gui,加载本本工程编译的程序集.为了在Visual Studio .NET中自动运行NUnit-Gui,你需要建立NUnit-Gui作为你的启动程序:在 Solution Explorer里右击你的NunitQuickStart工程。在弹出菜单中选择属性。在显示的对话框的左面,点击Configuration Properties夹选择出现在Configuration Properties夹下的Debugging。在属性框右边的Start Action部分,选择下拉框的Program作为Debug Mode值。按Apply按钮设置nunit-gui.exe 作为Start Application。,你既可以键入nunit-gui.exe的全路径,也可使用浏览按钮来指向它。图4-3 帮助描述本步骤:
图 4-3:将NUnit-Gui 作为工程的测试运行器第5步.编译运行测试.
现在编译solution。成功编译后,开始应用程序。NUnit-Gui测试运行器出现。当你第一次开始NUnit-Gui,它打开时没有测试加载。从File菜单选择Oprn,浏览NUnitQuickStart.dll的路径。当你加载了测试的程序集,测试运行器为加载的程序集的测试产生一个可见的表现。在例子中,测试程序集仅有一个测试,测试程序集的结构如图4-4所示:
图 4-4: 测试程序集的测试在 NUnit-Gui中的视图按Run按钮。树的节点变为绿色,而且测试运行器窗口上的进度条变绿,绿色代表成功通过。4.其他的一些核心概念
上面的例子介绍了基本的NUnit特性和功能. TestFixture, Test, 和 Assert是3个最基本的特征,我们可以用这些特性进行程序员测试了.但是有的时候,你觉得这3个远远不够,比如有的时候打开一个数据库连接多次,有没有只让它打开一次的方法呢?如果我想把测试分类,应该怎样实现呢?如果我想忽略某些测试,又应该如何去完成呢?不用担心,NUnit已经有这样的功能了.下面我们一一作出回答.SetUp/TearDown 属性
在早期给的test fixture定义里,我们说test fixture的测试是一组常规运行时资源.在测试完成之后,或是在测试执行种,或是释放或清除之前,这些常规运行时资源在一确定的方式上可能需要获取和初始化.NUnit使用2个额外的属性:SetUp 和TearDown,就支持这种常规的初始化/清除.我们上面的例子来描述这个功能.让我们增加乘法.1using System;
2using NUnit.Framework;
3
4namespace NUnitQuickStart
5{
6 [TestFixture]
7 public class NumersFixture
8 {
9 [Test]
10 public void AddTwoNumbers()
11 {
12 int a=1;
13 int b=2;
14 int sum=a+b;
15 Assert.AreEqual(sum,3);
16 }
17 [Test]
18 public void MultiplyTwoNumbers()
19 {
20 int a = 1;
21 int b = 2;
22 int product = a * b;
23 Assert.AreEqual(2, product);
24 }
25
26 }
27}
28
1using System;
2using NUnit.Framework;
3
4namespace NUnitQuickStart
5{
6 [TestFixture]
7 public class NumersFixture
8 {
9 private int a;
10 private int b;
11 [SetUp]
12 public void InitializeOperands()
13 {
14 a = 1;
15 b = 2;
16 }
17
18 [Test]
19 public void AddTwoNumbers()
20 {
21 int sum=a+b;
22 Assert.AreEqual(sum,3);
23 &n国民车竞争 吉利自由舰对比奇瑞旗云
2007-01-02 14:52:50
中国的国民车到底是哪一个?中国的国民车到底会由谁来造?这样的问题实际上在媒体上已经争论了好长时间的,一直到现在仍然没有一个定论。但有一点是能够肯定的,即中国的国民车只能由中国自己的车企业来造。自主品牌近年的强劲表现,也使人们更加坚定这个信念。今天,我们就将吉利和奇瑞代表产品自由舰和旗云进行对比,看看哪一个更接近国民车的要求。
吉利自由舰
奇瑞旗云
一、动力
发动机 最大功率(kW/rpm) 最大扭矩(N.m/rpm) 吉利自由舰1.6手动舒适型 MR481QA 78.7/6000
137/5200
奇瑞旗云之星1.6手动舒适型 Tritec 1.6 149/4500
149/4500
从表中可以看到,单从数据上来说,奇瑞旗云之星1.6的发动机要明显优于吉利自由舰1.6的发动机。旗云配备的Tritec发动机在MINI车上也有应用。不仅如此,由于Tritec发动机优秀的性能力帆520,福美来2也都车型配备该款发动机。至于吉利MR481QA发动机,我们要搞清楚这款发动机的特点,也看看这款发动机的来历。吉利首先根据5A又开发了1.5升的MR479QA发动机,随后才发展出来了1.6L的MR481QA发动机。因此,MR481QA是可以说继承了丰田的技术基因。在实际使用中,该款发动机也相当省油。
二、外形空间
吉利自由舰内部
奇瑞旗云内部
长/宽/高(mm) 轴距(mm) 吉利自由舰 4152/1680/1440
2434
旗云之星1.6 手动舒适型 4393/1682/1424
2468
就外形而言,自由舰显得更为时尚些,特别是前脸的拥有黑眼线的大灯很是有神。旗云在外形上显得有些保守,但方方正正的尾部还是很符合中国消费者口味的。在空间上,旗云要比自由舰更大。从表中数据上我们可以看到,旗云在外部尺寸和轴距上都要超过自由舰。
三、配置
旗云之星1.6 手动舒适型 吉利自由舰手动舒适型 ABS 有
有
EBD 有
有
车内油箱盖开关控制 无
有
后窗除霜器 无
有
电动侧视镜 无
有
在配置上,ABS,EBD都成为了两车标配,这一点难能可贵。但自由舰在配置上更为丰富。自由舰拥有车内油箱盖开关控制、车内油箱盖开关控制、后窗除霜器电动侧视镜等实用配置,使自由舰显得相当超值。
总结:
整体而言,旗云在空间上更大,更加适合三口之家使用。自由舰外形更加时尚,更易获得年轻人欢迎。当然,买车不能仅看外形。对于这一个级别的车型而言,汽车的使用费用是关键。根据两车提供的厂家提供油耗参数来看,旗云理论油耗百公里为5.3升,自由舰则为6.5升。但从实际使用过程中来看,两车油耗不分上下。另外,在车辆保养和维修上,两车也基本上处于同一个水平之上。
人们说的两厢、三厢车是什么意思
2007-01-02 11:27:05
《汽车知识》答复:单厢、两厢和三厢车都没有明确的定义。通俗地说,所谓的三厢车就是指平时常见的桑塔纳、捷达、奥迪A6这些前面有“鼻子”(发动机舱),后面有“屁股”(后备行李舱)的轿车;而两厢车则指少了突出的“屁股的轿车,例如街上经常可以见到的富康、POLO等车型;人们理解的单厢车则多指雷诺风景、神龙毕加索以及丰田大霸王这类MPV车型。
从结构上来说,如果整车的发动机舱、乘员舱、后备行李舱全部被分隔开,并且这种分隔是固定不可逆转的,那么就应该算是三厢车。两厢车指车身有后备行李舱但没有突出车体,这种情况下实际上乘员舱和后备行李舱是一体的,只是借助后排座椅等分隔开。所谓单厢车,其实是面包车(厢式车)的高级变种。是我们非常熟悉的面包车型,大的有丰田海狮、三菱得利卡等,小的有我们熟悉的长安面包车,这种车空间较大,既可载客,也可拉货,很实惠,但这种车也有个致命的缺点,就是没有单独的引擎舱,在发生正面撞击时没有缓冲。由于严格的安全法规,除日本外,北美和欧洲已禁止生产这种原始形态的“单厢车”。但受该车型的启发,结合两厢车和面包车的特点,产生出了颇具魅力的新型的“单厢车”。世界上最成功的单厢车是雷诺风景和雪铁龙的毕加索。单厢车虽然与两厢车越来越接近,但如果你仔细比较一下单厢车的代表毕加索与两厢车的代表高尔夫你就会发现有区别的地方还是很多。快乐的跨入2007年
2007-01-01 00:46:19
07到拉,新的一年,新希望,很多美好的事情希望都能在这年完成。
首要解决个人问题,特想有人能陪我一起去北京看08奥运。其次解决收入问题,高级讲师是这年的奋斗目标。
年龄不小拉!明显感到时间紧迫,加油加油!!
LoadRunner下DLL的调用
2006-12-30 01:52:06
今天看了51Testing陈卫俊(落叶夏日)的这篇文章非常好,特转来保存。谢过场景介绍
最近在做类似于QQ的通信工具的性能测试时发现了一些问题,现总结出来与大家分享一下。希望大家在使用LoadRunner时不仅仅停在只是录制/播放角本,而全面提升角本的编程技术,解决复杂场景。
本次测试中碰到的问题是这样的,在消息的传送过程中遇到了DEC加密的过程,LoadRunner录制到的全是加密的消息,比如我录制了某一个用户的登陆,发送消息,退出,但由于是加密的,只能单个用户使用,但如果我想并发多少个用户就存在很多问题,最直接的一个问题就是用户名是加密的,密码是加密的,当然你可以说让程序那里注掉加密的代码进行明码的测试,当然也是一种办法。但程序组提出了要使用更真实的方法来模拟,这时就必需使用下面介绍的方法。
一开始是直接把API移植到LoadRunner中来,不过由于加密算法异常复杂,有几层循环,而角本是解释执行的,进行一次加密运算可能需要好几分钟,当然在角本里可以把角本本身运行的时间去掉,但这样做显然没有直接调用DLL来的效率高。由于程序组比较忙,所以无法提供DLL给测试,所以测试完成了DLL的编写,并在LoadRunner中调用成功,高效的完成了用户信息加密,参数关联,成功的完成了测试。
动态链接库的编写
在Visual C++6.0开发环境下,打开FileNewProject选项,可以选择Win32 Dynamic-Link Library建立一个空的DLL工程。
1. Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库
每一个DLL必须有一个入口点,这就象我们用C编写的应用程序一样,必须有一个WINMAIN函数一样。在Non-MFC DLL中DllMain是一个缺省的入口函数,你不需要编写自己的DLL入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果应用程序的DLL需要分配额外的内存或资源时,或者说需要对每个进程或线程初始化和清除操作时,需要在相应的DLL工程的.CPP文件中对DllMain()函数按照下面的格式书写。
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}
参数中,hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);ul_reason_for_call是一个说明动态库被调原因的标志,当进程或线程装入或卸载动态链接库的时候,操作系统调用入口函数,并说明动态链接库被调用的原因,它所有的可能值为:DLL_PROCESS_ATTACH: 进程被调用、DLL_THREAD_ATTACH: 线程被调用、DLL_PROCESS_DETACH: 进程被停止、DLL_THREAD_DETACH: 线程被停止;lpReserved为保留参数。到此为止,DLL的入口函数已经写了,剩下部分的实现也不难,你可以在DLL工程中加入你所想要输出的函数或变量了。
我们已经知道DLL是包含若干个函数的库文件,应用程序使用DLL中的函数之前,应该先导出这些函数,以便供给应用程序使用。要导出这些函数有两种方法,一是在定义函数时使用导出关键字_declspec(dllexport),另外一种方法是在创建DLL文件时使用模块定义文件.Def。需要读者注意的是在使用第一种方法的时候,不能使用DEF文件。下面通过两个例子来说明如何使用这两种方法创建DLL文件。
1)使用导出函数关键字_declspec(dllexport)创建MyDll.dll,该动态链接库中有两个函数,分别用来实现得到两个数的最大和最小数。在MyDll.h和MyDLL.cpp文件中分别输入如下原代码:
//MyDLL.h
extern "C" _declspec(dllexport) int desinit(int mode);
extern "C" _declspec(dllexport) void desdone(void);
extern "C" _declspec(dllexport) void des_setkey(char *subkey, char *key);
extern "C" _declspec(dllexport) void endes(char *block, char *subkey);
extern "C" _declspec(dllexport) void dedes(char *block, char *subkey);
//MyDll.cpp
#include"MyDll.h"
//这里我用了比较大小的函数代替了我要实现的函数
int desinit(int a, int b)
{
if(a>=b)return a;
else
return b;
}
int desdone(int a, int b)
{
if(a>=b)return b;
else
return a;
}
该动态链接库编译成功后,打开MyDll工程中的debug目录,可以看到MyDll.dll、MyDll.lib两个文件。LIB文件中包含DLL文件名和DLL文件中的函数名等,该LIB文件只是对应该DLL文件的"映像文件",与DLL文件中,LIB文件的长度要小的多,在进行隐式链接DLL时要用到它。读者可能已经注意到在MyDll.h中有关键字"extern C",它可以使其他编程语言访问你编写的DLL中的函数。
LoadRunner调用动态链接库
上面完成动态链接库开发后,下面就介绍动态链接库如何被LoadRunner进行调用,其实也是很简单的。在LoadRunner中的DLL调用有局部调用与全局调用,下面介绍局部调用。
首先把你编译的DLL放在角本路径下面,这里是MyDll.dll,MyDll.lib.然后在Action中使用
lr_load_dll("MYDll.dll"),此函数可以把DLL加载进来,让你调用DLL里面的函数,而DLL中的运算是编译级的,所以效率极高,代码样例如下:
#include "lrs.h"
Action()
{
//
int nRet = 6;
char srckey[129];
memset(srckey, 'a', 128);
lr_message(lr_eval_string(srckey));
lr_load_dll("MyDLL.dll");
nRet = desinit(5,8);
lr_message("比较的结果为%d",nRet);
return 0;
}
运行结果
比较的结果为8
全局的动态链接库的调用则需要修改mdrv.dat,路径在LoadRunner的安装目录下面(LoadRunner/dat directory);在里面修改如例:
[WinSock]
ExtPriorityType=protocol
WINNT_EXT_LIBS=wsrun32.dll
WIN95_EXT_LIBS=wsrun32.dll
LINUX_EXT_LIBS=liblrs.so
SOLARIS_EXT_LIBS=liblrs.so
HPUX_EXT_LIBS=liblrs.sl
AIX_EXT_LIBS=liblrs.so
LibCfgFunc=winsock_exten_conf
UtilityExt=lrun_api
ExtMessageQueue=0
ExtCmdLineOverwrite=-WinInet No
ExtCmdLineConc=-UsingWinInet No
WINNT_DLLS=user_dll1.dll, user_dll2.dll, ...
//最后一行是加载你需要的DLL
这样你就可以在LR中随意的调用程序员写的API函数,进行一些复杂的数据加密,准备的一些操作,进行复杂的测试。同时如果你觉的有大量高复杂的运算也可以放在DLL中进行封装,以提高效率。
清空Cookie - 联系我们 - 51Testing软件测试网 - 交流论坛 - 空间列表 - 站点存档 - 升级自己的空间
Powered by 51Testing
© 2003-2021
沪ICP备05003035号