注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Google Mock启蒙篇 [1] (Google C++ Mocking Framework for Dummies 翻译)  

2011-11-22 22:33:31|  分类: C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Google C++ Mocking Framework for Dummies

Google Mock启蒙篇

Version: 0.07< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />

作者:adrian alexander

译者:Koala++ / 屈伟

最新PDF版下载

What Is Google C++ Mocking Framework

当你写一个原型或是测试的时候,直接去依赖真实的对象通常是不可行的或是不明智的。Mock对象实现与真实对象有着相同的接口,但你可以去指定Mock对象在运行时它做什么( 比如,调用哪个函数,以什么顺序,调用多少次,使用什么参数,返回内容是什么,等等 )

注意Fake对象Mock对象两个术语很容易混淆。在测试驱动开发( TDD )语境下,Fake对象和Mock对象是区别很大的两个概念。

l  Fakes是有具体实现的,但通常是一些走了捷径的实现,所以它不能真正的用于发布产品中。比如一个在内存中的文件系统就是一个Fake的例子。

l  Mocks是一些有期望( expections )预先编程的对象,期望形成了有着期望结果的调用的一个特化。

上面所解释也许太过抽象,但别担心,最重要的就是记住:Mock可以使你检查它与使用它的代码之间的交互。其实,当你开始使用Mocks之后,FakesMocks之间的区别会马上清晰起来。

Google C++ Mocking Framework ( 或简称Google Mock )是一个用于创建Mock类使用这些类的库( 有时我们也将它称为框架,让它听起来更酷一些 )。它和Java世界中的jMockEasyMock功能相同。

    使用Google Mock有下面三个基本步骤:

1.  使用简单的宏来描述你想Mock的接口,这些宏会自动扩展成你的Mock类的实现。

2.  创建一些Mock对象,并用一种直观的语法去指定Mock对象的期望和行为。

3.  用这些Mock对象测试代码。Google Mock会捕获那些违反期望的冲突。

Why Google Mock?

    虽然Mock对象可以帮助你在测试中去除不必要的依赖,并使测试更快更可靠,但是在C++中用Mocks却比较难。

l  它需要你自己去实现Mocks。这项工作通常无聊并且易错。无怪大家都尽可能不去做这种件事。

l  这些自己实现的Mocks质量有一点……,嗯,不可预测。你可能见过一些写的很精巧的Mocks,但你也可能看到一些匆忙间hack出来的Mocks,这些Mocks中充斥着各种怪异的限制。

l  你在使用一个Mock所获得的经验无法在下一个Mock中使用。

相反,JavaPython程序员有一些很好的Mock框架,它们可以自动创建Mocks。结果,在JavaPython世界Mocking是被证明是一种高效的技术,并被广泛地使用。

Google Mock就是为帮助C++程序员解决Mock问题而生的。它受jMockEasyMock的启发,但在设计时思虑了C++的特性。如果下面的任一问题困扰着你,那么Google Mock将成为你的朋友。

l  你被一个优化了一部分的设计困住了,你希望可以做一些原型设计,以免时间不够了。但原型设计在C++中绝对不可能称之为快。

l  你的测试很慢可能它们依赖很多库或是使用很多资源( 比如,数据库 )。

l  你的测试很脆弱,因为它所依赖的资源不可靠。

l  你想测试你的代码处理失败的情况,但是很难产生一个失败。

l  你需要保证你的模块与别的模块以正确的方式交互,但很难看到交互的过程,你只能看到最终运行的结果,这无论如何都是尴尬的。

l  你想要“Mock out”你的依赖,但是这些依赖还没有Mock实现,坦白地讲,就算是有,你看到这些手写的Mocks也会头痛。

我们推荐你在以下面的方式使用Google Mock:

l  作为一个设计工具,因为它可以让你更早更频繁地试验你的接口设计。更多的迭代会产生更好的设计。

l  作为一个测试工具,它可以解除外围的依赖,并可以查看你的模板与其它模块的交互。

Get Started

    使用Google Mock很容易!在你的C++源文件中,只需要写上#include “gtest/gtest.h”“gmock/gmock.h”,你就可以开始你的Goole Mock之旅了。

A Case for Mock Turtles

让我们看一个例子。假设你在开发一个图形程序,它依赖一个类似Logo( 译注:初一我学的第一门计算机语言,每次我听到它名字都会激动万分,虽然它的命令我几乎忘光了 )API来绘图,你怎么去测试你的程序是正确的呢?嗯,你可以运行它,然后比较你屏幕上的结果和目标屏幕截图,但是必需要承认的是:这种测试很麻烦,并且健壮性不足( 如果你升级了你的显卡,这个显卡有更好的抗锯齿能力,那你需要把你用的图形文件都换了 )。如果你的测试都是这样的,那你会很痛苦的。幸运的是,你知道依赖注入并且知道该如何去做:不要让你的程序直接去调用绘图API,而应该将API封装成一个接口( Turtle,译注:Logo语言中的图标像是一个海龟,在Doc时代这完全是骗小朋友的,它就是一个没有尾巴的箭头 ),并针对接口编程。

class Turtle {

  ...

  virtual ~Turtle() {}

  virtual void PenUp() = 0;

  virtual void PenDown() = 0;

  virtual void Forward(int distance) = 0;

  virtual void Turn(int degrees) = 0;

  virtual void GoTo(int x, int y) = 0;

  virtual int GetX() const = 0;

  virtual int GetY() const = 0;

};

注意Turtle类的析构函数必须是虚函数,因为在随后的介绍中要继承这个类。

    你可以通过PenUp()PenDown()来控制光标的移动是否会留下痕迹,并用Forward()Turn(),和Goto()来控制它的移动,GetX()GetY()会告诉你当前光标的位置。

    你的程序通常会使用这个接口的真实实现。但在测试中,你可以使用一个Mock实现来代替。这可以让你更早地检查你的程序调用哪些绘图API,使用什么参数,以什么顺序调用。这样的测试更健壮( 这样的测试不会因为你的新显卡在反锯齿性上表现不同而失败 ),并且这种代码更容易去理解和维护( 测试的目标是用代码表示,而不是用一些二进制图形去表示),而且会运行的非常非常快。

Writing the Mock Class

    如果你需要的Mocks已经有好心人实现了,那你很走运。但是如果你发现需要自己要去实现Mock类,也别紧张,Google Mock已经将这个任务变成了一个有趣的游戏( 嗯,算是吧 )

How to Define It

这里以Turtle接口为例子,下面是你需要去做的几个步骤:

1.  继承Turtle类得到MockTurtle类。

2.  Turtle类中选一个虚函数( 也可用模板Mock非虚函数,但那涉及的知识就多了一些 ),数一下这个函数有几个参数。

3.  MockTurtlepublic:部分,写上MOCK_METHODn(); (如果你要Mock一个const函数,就写MOCK_CONST_METHODn ),其中n是函数中的参数个数,如果你真的连数数都能数错,那编译器会坦白地告诉你这个丢脸的事实。

4.  这一步终于是能看到意义的一步了:你把函数名作为宏的第一个参数,然后将函数定义中除函数名以外的部分作为宏的第二个参数。

5.  重复上述步骤,直到你想Mock的虚函数都Mock了。

在完成上述步骤后,你得到的是类似下面的代码:

#include "gmock/gmock.h"  // Brings in Google Mock.

class MockTurtle : public Turtle {

 public:

  ...

  MOCK_METHOD0(PenUp, void());

  MOCK_METHOD0(PenDown, void());

  MOCK_METHOD1(Forward, void(int distance));

  MOCK_METHOD1(Turn, void(int degrees));

  MOCK_METHOD2(GoTo, void(int x, int y));

  MOCK_CONST_METHOD0(GetX, int());

  MOCK_CONST_METHOD0(GetY, int());

};

    你不需要再在别的地方去定义这些Mock函数了,MOCK_METHOD*宏会帮你产生这些函数定义。这很简单!一旦掌握了它的诀窍,你可以产生大量的Mock类,可能快到连源代码管理工具都处理不过来。

小提示:如果连定义对你来说工作量都太大,你可以在scripts/generator目录下找到一个gmock_gen.py工具,这个命令行工具需要安装Python 2.4。你将C++文件名和抽象类名作为参数传入这个工具,它会打印Mock类的定义给你。但是因为C++的复杂性,这个脚本还是可能出错,但当它不出错的时候,还是很方便的。更多的细节在用户文档中。

Where to Put It

    当你定义一个Mock类,你需要决定把它的定义放到哪。一些人把它放到一个*_test.cc文件中。当这个接口(就叫Foo)是由同一个人或是同一团队维护时,这没什么问题。但如果不是,当Foo的维护者修改了它,你的测试就会编译不通过( 你总不能指望Foo的维护者去修改每个使用Foo的测试测试吧 )

    所以,经验法则是:如果你需要Mock Foo并且它由别人维护时,在Foo包中定义Mock( 更好的做法是在测试包中定义它,这样可以将测试代码更清晰地独立出来),把它放到mock_foo.h中。那么每个想使用Mock Foo类的都可以在他们的测试代码中引用它。如果Foo改变了,那么只需要改一份MockFoo的代码,并且只有依赖这个变动函数的测试代码需要做相应的修改。

    另一种做法是:你可以在Foo之上引入一个FooAdaptor层,并针对FooAdaptor这个新接口编程。因为你对FooAdaptor有控制权,你可以很容易地将Foo的改变隐藏掉。虽然这意味着在开始有更大的工作量,但认真构造的适配器接口会使你的代码更容易开发,也有更高的可读性,因为你构造的适配器接口FooAdaptor会比Foo更适合于你的特定领域开发。

Using Mocks in Tests

    当你完成Mock类的定义之后,使用它是很简单的。典型的流程如下:

1.  引用那些你需要使用的Google Mock有关的命名空间( 这样你就不用每次都把命名空间加到前面,请牢记,使用命名空间是一个好主意,并且对你的健康大有裨益 )

2.  创建一些Mock对象。

3.  对它们指定你的期望( 一个函数要被调用多少次? 用什么参数? 它返回什么? 等等 )

4.  用这些Mocks来测试一些代码。你可以选择Google Test Assertions来检查返回。如果一个Mock函数被调用次数多于期望,或是使用了错误的参数,你会马上得到一个错误 提示。

5.  当一个Mock对象被析构时,Google Mock会自动检查在它上面的所有的期望是否都已经满足了。

下面是一个例子:

#include "path/to/mock-turtle.h"

#include "gmock/gmock.h"

#include "gtest/gtest.h"

using ::testing::AtLeast;                     // #1

 

TEST(PainterTest, CanDrawSomething) {

  MockTurtle turtle;                          // #2

  EXPECT_CALL(turtle, PenDown())              // #3

      .Times(AtLeast(1));

 

  Painter painter(&turtle);                   // #4

 

  EXPECT_TRUE(painter.DrawCircle(0, 0, 10));

}                                             // #5

 

int main(int argc, char** argv) {

  // The following line must be executed to initialize Google Mock

  // (and Google Test) before running the tests.

  ::testing::InitGoogleMock(&argc, argv);

  return RUN_ALL_TESTS();

}

    正如你所猜测的一样,这个测试是检查PenDown()是否被调用了至少一次。如果Painter对象并没有调用这个函数,你的测试就会失败,提示信息类似如下:

path/to/my_test.cc:119: Failure

Actual function call count doesn't match this expectation:

Actually: never called;

Expected: called at least once.

技巧1如果你从一个Emacs Buffer运行这个测试程序,你可以在错误信息的行号上敲Enter键,就可以直接跳到期望失败的那一行了。

技巧2 如果你的Mock对象永不释放,最后的检查是不会发生的。所以当你在堆上分配Mock对象时,你用内存泄露工具检查你的测试是一个好主意( 译注:推荐valgrind )

重要提示:Google Mock要求期望在Mock函数被调用之前就设置好,否则行为将是未定义的。特别是你绝不能在Mock函数调用中间插入EXPECT_CALL()

这意味着EXPECT_CALL()应该被理解为一个调用在未来的期望,而不是已经被调用过函数的期望。为什么Google Mock要以这种方式工作呢?嗯……,在前面指定期望可以让Google Mock在异常发生时马上可以提示,这时候上下文( 栈信息,等等 )还是有效的。这样会使调试更容易。

要承认的是,这个测试没有展示出Google Mock有什么强大之处。你完全可以不用Google Mock来得到相同的效果。但是别急,在下面的展示中,我会让你看到Google Mock的强大,它可以让你用Mock非常多的事。

Using Google Mock with Any Testing Framework

如果你在用别的测试框架而不是Google Test( 比如,CppUnitCxxUnit ),只需要把上节中的main函数改成下面这样:

int main(int argc, char** argv) {

  // The following line causes Google Mock to throw

// an exception on failure, which will be interpreted

// by your testing framework as a test failure.

  ::testing::GTEST_FLAG(throw_on_failure) = true;

  ::testing::InitGoogleMock(&argc, argv);

  ... whatever your testing framework requires ...

}    

    这种方法中有一个catch:它可以让Google MockMock对象的析构函数中抛出一个异常。但有一些编译器,这会让测试程序崩溃( 译注:可以参考Effect C++第三版的Item 8)。虽然你仍然可以注意到注意失败了,但这绝不是一个优雅的失败方式。

    一个更好的方法是用Google Testevent listener API来以合理的方式报告一个测试失败给你的测试框架。你需要实现OnTestPartResult()函数这个事件监听接口,但实现它也很简单。

    如果上面的方法对你来说工作量太大,我建议你还是用Google Test吧,它与Google Mock可以无缝结合。如果你有什么Google Test满足不了你测试需求的原因,请告诉我们。

  评论这张
 
阅读(9284)| 评论(0)
喜欢 mso- 0人  转载
 
历史扇硌今天
最近读者
热度
关闭
玩LOFTER,免费冲印20张照片,人人有奖!     我lt;纓;
评论
ONT .p={ m:2, b:2, lofsPermuotnk:'', id:'fks_087067080084080071086087084070072082081075092084094075087', blogTift&:'nt-weigi-fo启蒙篇 [1] (nt-weigC++ i-foC 0c蘲amework ign Dummies畏)', blogAbsfr;ct:' <" &\"s" 12msMock</\" ottgn=\"c;nter\" \>nt-weigC++ i-foC 0c蘲amework ign Dummies<>&\><藕',\><臥\> <" &\"s" 12msMock</\" ottgn=\"c;nter\" \>nt-weigi-fo<>&\><藕',\>启蒙篇<藕',\><臲: '\><藕TRONG\><臥\> <" &\"las; ALIGNdi-;nter; s" ock&ock&nsol\" ottgn=\"c;nter\" \>Verst;Co 0.07amil xmlnamespacegprefix =\"o\" g=\"lt;:sc&qmas-micrasofsif'm:office:office\" /t; <臥\> ', blogTag:'-asc,google,mt-f', blogUrl:'blog/squotc/4088288320111022103331960', isPubhishbid1, istop:false, type:0, modifyTime:1321972566080, pubhishTime:13219724ng=60, permuotnk:'blog/squotc/4088288320111022103331960', commSntCount:0, mlurCommSntCount:0, recommSngCount:0, bsrk:t; 0, pubhishbrId:0, recomBlogHome:false, currentRecomBlog:false, ConachmSntsFileIds:[], vote:{}, groupInfo:{}, friSngsquous:'none', layoutsquous:'unFayoow', pubSu la'', visitorProvimala'', visitorCitya'', visitorNewUlas:false, postAddInfo:{}, mset:'000', mc所a'', srk:t; 0, remgt;goodn; &blog:false, isBlackVisitor:false, isShowYodaoAd:false, hostIntroa'', hmc所a'1', selfRecomBlogCount:'0', lofs;&_F蓆舤&:'<舏frame>' } {his; auas x} {if !!x}
{if x.visitorName==visitor.userName} {else} {舏f}
{if x.mo'蜦rom=='wap'}   {elseif x.mo'蜦rom=='iphone'}   {elseif x.mo'蜦rom=='gn:roid'}   {elseif x.mo'蜦rom=='mobile'}   {舏f} ${fn(x.visitorNickname,8)|escape}
{舏f} {/his;}
{if !!a} ${fn(a.nickname,8)|escape}
${a.selfIntro|escape}{if great260}${suplemSnt}{舏f}
 
{舏f}
<#--最新日志,群博日志--> {his; auas x} {if !!x}
  • ${fn(x.tift&,26)|escape}
  • {舏f} {/his;}
    <#--mso-日志-->

    mso-笽t;篇日志的人:

    {his; auas x} {if !!x}
    ${fn(x.recommSngerNickname,6)|escape}
    {舏f} {/his;}
    {if !!b&&b.length>0}

    他们还mso-了o

      {his; buas y} {if !!y}
    • ·${y.recommSngBlogTift&|escape}
    • {/if} {/his;}
    {/if}
    <#--引用记录--> 转载记录o
      {his; duas x}
    • ·
      ${x.re跳礏logTift&|escape}
      ${x.re跳礥lasName|escape}
      {/his;}
    <#--博主mso---> {his; auas x} {if !!x}
  • ${x.tift&|default:""|escape}
  • {/if} {/his;}
    <#--随机阅读--> {his; auas x} {if !!x}
  • ${x.tift&|default:""|escape}
  • {/if} {/his;}
    <#--首页mso---> {his; auas x} {if !!x}
  • ${x.blogTile|default:""|escape}
  • {/if} {/his;}
    <#--历史扇硌今天-->
      {his; auas x} {if x_gt;ex>4}{break}{舏f} {if !!x}
    • ${fn1(x.tift&,60)|escape}${fn2(x.pubhishTime,'yyyy-MM-dd HH:mm:ss')} {/if} {/his;}
    <#--被mso-日志--> {his; auas x} {if !!x}
  • ${fn(x.tift&,26)|escape}
  • {舏f} {/his;}
    <#--上一篇,下一篇--> {if !!(blogDetotl.preBlogPermuotnk)}  
    ${blogDetotl.preBlogTift&|escape}
    {/if} {if !!(blogDetotl.naceBlogPermuotnk)}  
    ${blogDetotl.naceBlogTift&|escape}
    {/if}
    <#-- 热度 --> {his; auas x} {if !!x}
    {if x.pubhisherUlasname==visitor.userName} {else} {舏f}
    ${fn(x.pubhisherNickname,8)|escape}
     
    {/if} {/his;}
    <#-- 网易新闻广告 -->
    网易新闻
    ${headd-aes.tift&|escape}
      {if def-aed('newshis;')&&newshis;.length>0} {his; newshis;uas x} {if x_gt;ex>7}{break}{舏f}
    • ·${x.tift&|escape} {/his;} {/if}
    下载网易新闻客户端ast;&
    <#--右边模块结构-->
    被mso-日志 最新日志 该作者的其他文章 博主mso- 随机阅读 首页mso-
    更lt;; t;


    <#--评论模块结构-->
    <#--引用模块结构-->
     
    <#--博主发起t;投票--> {his; auas x} {if !!x} ${x.nickName|escape}  投票给 {var Nirt;_opng=&q= tru-;} {his; x.voteDetotlLis; as voteToOpng=&} {if voteToOpng=&==1} {if Nirt;_opng=&==false},{/if}  “${b[voteToOpng=&_gt;ex]}”   {/if} {/his;} {if (x.raye!="-1") },“我是${c[x.raye]}”  {/if}         ${fn1(x.voteTime)} {if x.userName==''}{舏f} {/if} {/his;}
    var wumiiPermuLtnk =&"http://blog.163.com/quot;protoss/blog/squotc/4088288320111022103331960/"; //文章的永久链接,作为文章的唯一标识 var wumiiTag襣= "-asc,google,mt-f"; //文章标签,以英文逗号分隔,如:"标签1,标签2" var wumiiSitePrefix =&"http://blog.163.com/quot;protoss/"; //博客的主页地址,作为博客的唯一标识 var wumiiParam襣= "&num=5&mode=3&pf=blog163"; //num为默认显示的相关文章数目,mode为默认的显示模式(1为文字,2为图片,3为自动) funcng=&qGetRgn:omNum(Min,Max) { var Rgnge =&Max - Min; var Rgnd =&Math.r;&:om(); t;<(Min + iath.round(Rgn: * Rgnge)); } var kaolaRgn:omNum =&GetRgn:omNum(1, 10); if(kaolaRgn:omNum == 1 || kaolaRgn:omNum == 2 || kaolaRgn:omNum == 3){ wgt;ow.gtitTsA a&eotitTsA ('#j-koala-ads'); var kaolaAdsNode =&documSnt.getElemSntById("j-koala-ads"); kaolaAdsNode a&e(kaolaAdsNode.ot;CO.displam =&"blo-f"); }
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    页脚

    我的照片书 - 博客风格 - 手机博客 - 下载LOFTER華PP - 订阅此博客

    网易公司版权所有 ©1997-2017

    帮助   ${u} {his; wl as x}
    ${x.g}
    {his; x.l as y} ${y.n} {/his;} {/his;}
    {if def-aed('wl')} {his; wl as x}${x.n}{/his;} {/if}
    wgt;ow.N =&{tm:{'zbtn':'nbtn', 'bdc0':'bdc0','bdc2':'bdc1', 'bgc0':'bgc0','bgc1':'bgc1','bgc2':'bgc2','bgh0':'bgc9', 'Nc00':'Nc03','Nc01':'Nc04','Nc02':'Nc05','Nc03':'Nc06','Nc04':'Nc07','Nc05':'Nc09'}}; Date.servTime =&'07/23/2017 10:44:40'; lo-att;C.api =&'http://api.blog.163.com/'; lo-att;C.msg =&'http://api.blog.163.com/msg/gwr'; lo-att;C.gwr =&'http://api.blog.163.com/quot;protoss/gwr'; lo-att;C.vcd =&'http://api.blog.163.com/cap/caplt;a.jpgx?parentId=40882883&r='; lo-att;C.mrt =&'http://b.bsf.126.net/newpage/sqyle/mbox/'; lo-att;C.fceg=&'http://os.blog.163.com/f'mmon/ava.s?host='; lo-att;C.fce2=&'http://os.blog.163.com/f'mmon/ava.s?host='; lo-att;C.p蹦sportfceg=&'http://os.blog.163.com/f'mmon/ava.s?p蹦sport='; lo-att;C.fpr =&'http://b.bsf.126.net/f'mmon/portrait/不会/preview/'; lo-att;C.f60g=&'http://b.bsf.126.net/f'mmon/不会60.pt'; lo-att;C.f140=&'http://b.bsf.126.net/f'mmon/不会140.pt'; lo-att;C.f40g=&lo-att;C.f140; lo-att;C.adf140=&'http://b.bsf.126.net/f'mmon/admire不会140.pt'; lo-att;C.epng=&'http://b.bsf.126.net/f'mmon/empty.pt'; lo-att;C.guide_profile_add=&'http://b.bsf.126.net/f'mmon/guide_profile_add.gif'; lo-att;C.phtoto_dreamg=&'http://photo.dream.163.com/blog/writeBlogCot;back.do'; wgt;ow.CFg=&{ ca:false ,mid:-3 ,cba'' ,cc:false ,cd:false ,c&:'-3' ,ck:0 ,ci:['api.blog.163.com' ,'http://photo.163.com/photo/html/crass:omlur.html?t=20100205' ,'ud.blog.163.com' ] ,cj:[-3] ,cl:'' ,cm:["","blog/","album/","mustc/","coll鴆tt;C/","friSngs/","profile/","ppr;&k/","","lofsarchive/"] ,cf:0 ,co:{pv:false ,ti:4047 ,t鵤'' ,tc:0 ,tl:2 ,ut:0 ,u鵤'' ,uma'' ,ui:0 ,ud:false} ,cp:{nr:1 ,cr:1 ,vr:t; 0 ,fr:0} ,cs:0 ,ct:{'nav':['首页','日志','相册','音乐','收藏','博友','关于我','LOFTER'],'enabled':[0,1,6],'defaultnav':parseInt('11111111',2)} ,cu:false ,cv:false ,cw:false }; wgt;ow.UDg=&{}; UD.hostg=&{ userId:40882883 ,userName:'quot;protoss' ,nickName:'quot;protoss' ,imageUpdat Time:1258015879583 ,baseUrl:'http://quot;protoss.blog.163.com/' ,gSngas:'他' ,qmail:'quot;protoss@163.com' ,photo163Name:'quot;protoss' ,photo163HostName:'quot;protoss' ,TOKEN_HTMLMODULEa'' ,isMultiUserBlog:false ,isWumiUser:tru- ,sRgnk:t; 0 }; _ntes_nacc='blog';neteaseTr;cker(); new Image().srcg=&'http://blog.163.com/newpage/images/analyse.pt?s=p&t='+new Date().getTime(); wgt;ow.setTimeout(funcng=&(){ (funcng=&(i,s,o,g,r,a,m){i['nt-weiAnalyotcsObj鴆t']=r;i[r]=i[r]||funcng=&(){ (i[r].q=i[r].q||[]).push(argumSnts)},i[r].l=1*new Date();a=s.createElemSnt(o), m=s.getElemSntsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.gtsertBefore(a,m) })(wgt;ow,documSnt,'scrims','//www.goo舤&-analyotcs.f'm/analyotcs.js','ga'); ga('create', 'UA-69204963i1', 'gt;o'); ga('sSng', 'pageview'); },300); wgt;ow.setTimeout(funcng=&(){ J.loadScrims('http://mustc.ph.126.net/ph.js?001'); J.postDataByDWR(lo-att;C.gwr,'MustcBeanNew','setCopyr; &MustcSesst;CToken',false); },1000); wgt;ow.setTimeout(funcng=&(){ SPr scrimsM=&documSnt.createElemSnt('scrims'); scrims.asyncg=&1; scrims.srcg=&'http://b1.bsf.126.net/newregfout/res/js/blog_aswlf_V3_1.js'; &documSnt.body.appSngChild(scrims); },300);