<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>进化的测试 &#187; DSL</title>
	<atom:link href="http://magustest.com/blog/tag/dsl/feed/" rel="self" type="application/rss+xml" />
	<link>http://magustest.com/blog</link>
	<description>软件测试，自动化测试，白盒测试，Python</description>
	<lastBuildDate>Thu, 17 May 2012 14:19:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>DSL与自动化测试 – 用Python实现简单的DSL</title>
		<link>http://magustest.com/blog/python/dsl-automation-testing-using-python/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dsl-automation-testing-using-python</link>
		<comments>http://magustest.com/blog/python/dsl-automation-testing-using-python/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 06:15:32 +0000</pubDate>
		<dc:creator>magus</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[自动化测试]]></category>
		<category><![CDATA[DSL]]></category>

		<guid isPermaLink="false">http://magustest.com/blog/?p=655</guid>
		<description><![CDATA[自动化测试，一个在测试领域中被广为熟知，也是被谈论最多的概念之一。DSL (Domain Specific Language)，一种高度抽象，用于某个特定领域下编程语言。软件测试在大多数情况下都是对某个特定行业的软件系统进行测试，所以这两者应该可以很好的结合起来，事实上也是这样的，QTP里面的keyword view，其实就是DSL的一个实现。DSL一般可以分为两个大的类型，分别是External DSL 和 Internal DSL （引用自Martin Fowler）。External DSL 一般来说是跟其实现语言不一样的 DSL，常见的External DSL 有：SQL和XML配置文件；而Internal DSL 一般来说就是该DSL使用某个现成的编程语言（就是所谓的host language)，然后对host language进行一些改造而成。 我们在测试中会遇到很多问题，其中一些问题，几乎是所有公司所有团队都会遇到的，例如测试覆盖率不够，测试的时间不够等等。面对这些问题，自动化测试自然而然地成为解决这些问题的首选方法。但是自动化测试真的就是银弹麽？不见得！以前曾经在ASP.NET QA 的博客中给他们留言，请教过关于自动化测试的事情，我记得其中有一个回复是说，在某个release中过度地使用自动化测试，一切东西都想实现自动化测试，而忽略了产品本身的功能、特性的关注，结果就是超高的自动化测试覆盖率，但是很差的产品质量。大家都去实现自动化测试了，谁来做功能点的覆盖呢？某些领域的专家（SME），他们可能对测试技术是一无所知的，要把这些领域专家和测试实施结合起来，DSL就是一个比较好的桥梁。 我在工作中遇到的问题是，我需要测试一个类似UV（独立用户访问数）统计的系统，统计UV的方法其实就是根据_uid cookie的值来判断这个用户在某段时间内访问过我们的系统多少次，访问了哪些站点，进行了什么样的行为。其中有2个地方比较麻烦，第一就是在测试过程中要不断地拷贝cookie，这样拷来拷去两三次以后很容易就混乱，出错；第二就是需要记录访问哪些站点，这些站点都只是ID，也是需要不断地修改请求，测试时间长了也是很容易出错。所以我就打算在原来的测试工具基础上，实现一个简单的Internal DSL。先看成品： @tc def uniq_inventory_case01&#40;&#41;: test= testTool&#40;&#41; test.user&#40;'a'&#41;.view&#40;'asset55100002'&#41;.anetwork&#40;'55100'&#41;.onsite&#40;'site55100503'&#41;.snetwork&#40;'55100'&#41;.dnetwork&#40;'55100'&#41;.times&#40;1&#41;.go&#40;&#41; test.user&#40;'b'&#41;.view&#40;'asset55100002'&#41;.anetwork&#40;'55100'&#41;.onsite&#40;'site55100503'&#41;.snetwork&#40;'55100'&#41;.dnetwork&#40;'55100'&#41;.times&#40;2&#41;.go&#40;&#41; test.user&#40;'b'&#41;.view&#40;'asset55100002'&#41;.anetwork&#40;'55100'&#41;.onsite&#40;'site55100504_noad'&#41;.snetwork&#40;'55100'&#41;.dnetwork&#40;'55100'&#41;.times&#40;4&#41;.go&#40;&#41; 实例化一个testTool对象，然后就是指定哪个用户：user(&#8216;a&#8217;)或者user(&#8216;b&#8217;)，看的视频的ID：view(&#8216;asset55100002&#8242;)，这个视频属于哪个CRO呢？anetwork(&#8217;55100&#8242;)；放在哪个网站呢？onsite(&#8216;site55100503&#8242;)；网站是谁的呢？snetwork(&#8217;55100&#8242;)；谁是分发者呢？dnetwork(&#8217;55100&#8242;)；看了多少次呢？times(4)；最后一个有点儿丑陋的go()。 像这样子一句话里面N个方法连着用，就叫Method Chaining，Method Chaining通常可以让代码变得更加人性化，读起来更加容易。但是使用Method Chaining通常会遇到一个问题，就是很难判断就是到了哪个方法才是终结呢？是不是有些方法的调用是可选的，有些是必选的呢？其中一个解决方法就是我用到的，放一个.go()方法在最后，作为终结方法。要实现Method Chaining，其实只需要顶一个类，对于需要做连接的方法，最后都返回这个类的实例。例如： def view&#40;self, assetid&#41;: if assetid: self.asset_id = assetid return self &#160; def anetwork&#40;self, networkid&#41;: if <a href='http://magustest.com/blog/python/dsl-automation-testing-using-python/' class='excerpt-more'>[...]</a>
No related posts.]]></description>
			<content:encoded><![CDATA[<p>自动化测试，一个在测试领域中被广为熟知，也是被谈论最多的概念之一。DSL (Domain Specific Language)，一种高度抽象，用于某个特定领域下编程语言。软件测试在大多数情况下都是对某个特定行业的软件系统进行测试，所以这两者应该可以很好的结合起来，事实上也是这样的，QTP里面的keyword view，其实就是DSL的一个实现。DSL一般可以分为两个大的类型，分别是External DSL 和 Internal DSL （引用自Martin Fowler）。External DSL 一般来说是跟其实现语言不一样的 DSL，常见的External DSL 有：SQL和XML配置文件；而Internal DSL 一般来说就是该DSL使用某个现成的编程语言（就是所谓的host language)，然后对host language进行一些改造而成。</p>
<p>我们在测试中会遇到很多问题，其中一些问题，几乎是所有公司所有团队都会遇到的，例如测试覆盖率不够，测试的时间不够等等。面对这些问题，自动化测试自然而然地成为解决这些问题的首选方法。但是自动化测试真的就是银弹麽？不见得！以前曾经在ASP.NET QA 的博客中给他们留言，请教过关于自动化测试的事情，我记得其中有一个回复是说，在某个release中过度地使用自动化测试，一切东西都想实现自动化测试，而忽略了产品本身的功能、特性的关注，结果就是超高的自动化测试覆盖率，但是很差的产品质量。大家都去实现自动化测试了，谁来做功能点的覆盖呢？某些领域的专家（SME），他们可能对测试技术是一无所知的，要把这些领域专家和测试实施结合起来，DSL就是一个比较好的桥梁。</p>
<p>我在工作中遇到的问题是，我需要测试一个类似UV（独立用户访问数）统计的系统，统计UV的方法其实就是根据_uid cookie的值来判断这个用户在某段时间内访问过我们的系统多少次，访问了哪些站点，进行了什么样的行为。其中有2个地方比较麻烦，第一就是在测试过程中要不断地拷贝cookie，这样拷来拷去两三次以后很容易就混乱，出错；第二就是需要记录访问哪些站点，这些站点都只是ID，也是需要不断地修改请求，测试时间长了也是很容易出错。所以我就打算在原来的测试工具基础上，实现一个简单的Internal DSL。先看成品：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@tc
<span style="color: #ff7700;font-weight:bold;">def</span> uniq_inventory_case01<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">test</span>= testTool<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">test</span>.<span style="color: #dc143c;">user</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span>.<span style="color: black;">view</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'asset55100002'</span><span style="color: black;">&#41;</span>.<span style="color: black;">anetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">onsite</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'site55100503'</span><span style="color: black;">&#41;</span>.<span style="color: black;">snetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">dnetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">times</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>.<span style="color: black;">go</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">test</span>.<span style="color: #dc143c;">user</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'b'</span><span style="color: black;">&#41;</span>.<span style="color: black;">view</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'asset55100002'</span><span style="color: black;">&#41;</span>.<span style="color: black;">anetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">onsite</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'site55100503'</span><span style="color: black;">&#41;</span>.<span style="color: black;">snetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">dnetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">times</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>.<span style="color: black;">go</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">test</span>.<span style="color: #dc143c;">user</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'b'</span><span style="color: black;">&#41;</span>.<span style="color: black;">view</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'asset55100002'</span><span style="color: black;">&#41;</span>.<span style="color: black;">anetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">onsite</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'site55100504_noad'</span><span style="color: black;">&#41;</span>.<span style="color: black;">snetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">dnetwork</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'55100'</span><span style="color: black;">&#41;</span>.<span style="color: black;">times</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>.<span style="color: black;">go</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>实例化一个testTool对象，然后就是指定哪个用户：user(&#8216;a&#8217;)或者user(&#8216;b&#8217;)，看的视频的ID：view(&#8216;asset55100002&#8242;)，这个视频属于哪个CRO呢？anetwork(&#8217;55100&#8242;)；放在哪个网站呢？onsite(&#8216;site55100503&#8242;)；网站是谁的呢？snetwork(&#8217;55100&#8242;)；谁是分发者呢？dnetwork(&#8217;55100&#8242;)；看了多少次呢？times(4)；最后一个有点儿丑陋的go()。</p>
<p>像这样子一句话里面N个方法连着用，就叫Method Chaining，Method Chaining通常可以让代码变得更加人性化，读起来更加容易。但是使用Method Chaining通常会遇到一个问题，就是很难判断就是到了哪个方法才是终结呢？是不是有些方法的调用是可选的，有些是必选的呢？其中一个解决方法就是我用到的，放一个.go()方法在最后，作为终结方法。要实现Method Chaining，其实只需要顶一个类，对于需要做连接的方法，最后都返回这个类的实例。例如：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> view<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, assetid<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> assetid:     <span style="color: #008000;">self</span>.<span style="color: black;">asset_id</span> = assetid
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> anetwork<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, networkid<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> networkid:   <span style="color: #008000;">self</span>.<span style="color: black;">a_network_id</span> = networkid
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> snetwork<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, networkid<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> networkid:   <span style="color: #008000;">self</span>.<span style="color: black;">s_network_id</span> = networkid
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> dnetwork<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, networkid<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> networkid:   <span style="color: #008000;">self</span>.<span style="color: black;">d_network_id</span> = networkid
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> onsite<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, sectionid<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> sectionid:   <span style="color: #008000;">self</span>.<span style="color: black;">site_section_id</span> = sectionid
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> times<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, times<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> times<span style="color: #66cc66;">&gt;</span><span style="color: #ff4500;">0</span>:       <span style="color: #008000;">self</span>.<span style="color: black;">request_times</span> = times
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span></pre></div></div>

<p>最后一个终结方法go()，就做真正的处理</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> go<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">asset_id</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">self</span>.<span style="color: black;">site_section_id</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">self</span>.<span style="color: black;">times</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">self</span>.<span style="color: black;">a_network_id</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">self</span>.<span style="color: black;">s_network_id</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">prepareRequest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">request_times</span><span style="color: black;">&#41;</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">sendRequest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">cleanup</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        info = <span style="color: #483d8b;">'Required information missing, abort running.'</span>
        <span style="color: #dc143c;">logging</span>.<span style="color: black;">debug</span><span style="color: black;">&#40;</span>info<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> info</pre></div></div>

<p>如果是实现一个External DSL 的话，的确难度不小；但是Internal DSL其实并不是很高深，也不是很难实现，在它的帮助下，可以把工作完成的更好，对自己以后维护测试用例也带来了不少方便。</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://magustest.com/blog/python/dsl-automation-testing-using-python/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

