如何进行微服务的单元测试、集成测试和系统测试?
如何进行微服务的测试
对于测试工作而言,微服务架构对于传统的架构引入了更多的复杂性。一方面,随着微服务数量的增长,测试的用例也会持续增长;另一方面,由于微服务之间存在着一定的依赖性,在测试过程中如何来处理这些依赖,就变得极为重要。
本节将从微服务架构的单元测试、集成测试和系统测试三个方面来展开讨论。
微服务的单元测试
单元测试要求将测试范围局限在服务内部,这样可以保证测试的隔离性,将测试的影响减少到最小。在实际编码之前,TDD要求程序员先编写测试用例。当然,一开始,所有的测试用例应该是全部失败的,然后再写代码让这些测试用例逐个通过。也就是说,编写足够的测试用例使测试失败,编写足够的代码使测试成功。这样,程序员编码的目的就会更加明确。
当然,编写测试用例并非是TDD的全部。在测试成功之后,还需要对成功的代码及时进行重构,从而消除代码的“坏味道”。
1.为什么需要重构代码
所谓重构,简而言之,就是在不改变代码外部行为的前提下,对代码进行修改,以改善程序的内部结构。
重构的前提是代码的行为是正确的,也就是说,关于代码功能已经经过测试,并且测试通过了,这是重构的前提。只有正确的代码才有重构意义。
那么,既然代码都正确了,为什么还要花费时间再去改动代码、重构代码呢?
重构的原因是大部分程序员无法写出完美的代码。他们无法对自己编写的代码完全信任,这也是需要对自己所写的代码进行测试的原因,重构也是如此。归纳起来,以下几方面是软件需要重构的原因。
- ·软件不一定一开始就是正确的。天才程序员只是少数,大多数人不可避免会犯错,所以很多程序员无法一次性写出正确的代码,只能不断地测试、不断地重构,以改善代码。连MartinFowler这样的大师都承认自己的编码水平也同大多数人一样,是需要测试及重构的。
- ·随着时间推移,软件的行为变得难以理解。这种现象特别集中在一些规模大、历史久、代码质量差的软件里面。这些软件的实现,或者脱离了最初的设计,或者混乱不堪,让人无法理解,特别是缺少“活文档”来进行指导,这些代码最终会“腐烂变味”。
- ·能运行的代码,并不一定是好代码。任何程序员都能写出计算机能理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员。
正是目前软件行业这些事实的存在,促使重构成为TDD中必不可少的实践之一。程序员对程序进行重构,是出于以下的目的。
- 消除重复。代码在首次编码时,单纯只是为了让程序通过测试,其间可能会有大量的重复代码,以及“僵尸代码”的存在,所以需要在重构阶段消除重复代码。
- 使代码易理解、易修改。在一开始,程序员优先考虑的是程序的正确性,在代码的规范上并未加以注意,所以需要在重构阶段改善代码。
- 改进软件的设计。好的想法也并非一气呵成,当对以前的代码有更好的解决方案时,果断进行重构来改进软件设计。
- 查找Bug,提高质量。良好的代码不但能让程序员易懂易于理解,同样,也能方便程序员来发现问题,修复问题。测试与重构是相辅相成的。
- 提高编码效率和编码水平。重构技术利于消除重复代码,减少冗余代码,提升程序员的编码水平。程序员编码水平的提升,同时也将体现在其编码效率上。
2.何时应该进行重构
那么,程序员应该在何时进行重构呢?
- 随时重构。也就是说,将重构当作是开发的一种习惯,重构应该与测试一样自然。
- 事不过三,三则重构。当代码存在重复时,就要进行重构了。
- 添加新功能时。添加了新功能,对原有的代码结构进行了调整,意味着需要重新进行单元测试及重构。
- 修改错误时。修复错误后,同样也是需要重新对接口进行单元测试及重构的。
- 代码审查。代码审查是发现“代码坏味道”非常好的时机,自然也是进行重构的绝佳机会。
3.代码的“坏味道”
如果一段代码是不稳定或有一些潜在问题的,那么代码往往会包含一些明显的痕迹,就好像食物要腐坏之前,经常会发出一些异味一样,这些痕迹就是代码“坏味道”。以下就是常见的代码“坏味道”。
- DuplicatedCode(重复代码):重复是万恶之源。解决方法是将公共函数进行提取。
- LongMethod(过长函数):过长函数会导致责任不明确、难以切割、难以理解等一系列问题。解决方法是将长函数拆分成若干函数。
- LargeClass(过大的类):会导致职责不明确、难理解。解决方法是拆分成若干类。
- LongParameterList(过长参数列):过长参数列其实是没有真正地遵从面向对象的编码方式,对于程序员来说也是难以理解的。解决方法是将参数封装成结构或类。
- DivergentChange(发散式变化):当对多个需求进行修改时,都会动到这种类。解决方法是对代码进行拆分,将总是一起变化的东西放在一起。
- ShotgunSurgery(霞弹式修改):其实就是在没有封装变化处改动一个需求,然后会涉及多个类被修改。解决方法是将各个修改点集中起来,抽象成一个新类。
- FeatureEnvy(依恋情结):一个类对其他类存在过多的依赖,比如某个类使用了大量其他类的成员,这就是FeatureEnvy。解决方法是将该类并到所依赖的类里面。
- DataClumps(数据泥团):数据泥团是常一起出现的大堆数据。如果数据是有意义的,解决方法是就将结构数据转变为对象。
- PrimitiveObsession(基本类型偏执):热衷于使用int、long、String等基本类型。其解决方法是将其修改成使用类来替代。
- SwitchStatements ( switch惊悚现身):当出现 switch语句判断的条件太多时,则要考虑少用switch语句,采用多态来代替。
- ParallelInheritanceHierarchies(平行继承体系):过多平行的类,使用类继承并联起来。解决方法是将其中一个类去掉继承关系。
- LazyClass(冗赘类):针对这些冗赘类,其解决方法是把这些不再重要的类里面的逻辑合并到相关类,并删除旧的类。
- SpeculativeGenerality(夸夸其谈未来性):对于这些没有用处的类,直接删除即可。
- TemporaryField (令人迷惑的暂时字段):对于这些字段,解决方法是将这些临时变量集中到一个新类中去管理。
- MessageChains(过度耦合的消息链):使用真正需要的函数和对象,而不要依赖于消息链。
- MiddleMan(中间人):存在这种过度代理的问题,其解决方法是用继承替代委托。
- InappropriateIntimacy(狎昵关系):两个类彼此使用对方的private值域。解决方法是划清界限拆散,或合并,或改成单项联系。
- AlternativeClasseswithDifferentInterfaces(异曲同工的类):这些类往往是相似的类,却有不同的接口。解决方法是对这些类进行重命名、移动函数或抽象子类重复作用的类,从而合并成一个类。
- IncompleteLibraryClass(不完美的库类):解决方法是包一层函数或包成新的类。
- DataClass(纯稚的数据类):这些类很简单,往往仅有公共成员变量或简单的操作函数。解决方法是将相关操作封装进去,减少public成员变量。
- RefusedBequest(拒绝遗赠):这些类的表现是父类里面方法很多,但子类只用到有限几个。解决方法是使用代理来替代继承关系。
- Comments(过多的注释):注释多了,就说明代码不清楚了。解决方法是写注释前先重构,去掉多余的注释,“好代码会说话”。
4.减少测试的依赖
首先,我们必须承认,对象间的依赖无可避免。对象与对象之间通过协作来完成功能,任意一个对象都有可能用到另外对象的属性、方法等成员。但同时也认识到,代码中的对象过度复杂的依赖关系往往是不提倡的,因为对象之间的关联性越大,意味着代码改动一处,影响的范围就会越大,而这完全不利于系统的测试、重构和后期维护。所以在现代软件开发和测试过程中应该尽量降低代码之间的依赖。
相比于传统JavaEE的开发模式,DI(依赖注人)使代码更少地依赖容器,并削减了计算机程序的耦合问题。通过简单的new操作,构成程序员应用的 POJO对象即可在JUnit或TestNG下进行测试。即使没有Spring或其他loC容器,也可以使用mock来模拟对象进行独立测试。清晰的分层和组件化的代码将会促进单元测试的简化。例如,当运行单元测试的时候,程序员可以通过stub或mock来对DAO或资源库接口进行替代,从而实现对服务层对象的测试,这个过程中程序员无须访问持久层数据。这样就能减少对基础设施的依赖。
在测试过程中,真实对象具有不可确定的行为,有可能产生不可预测的效果(如股票行情、天气预报),同时,真实对象存在以下问题。
- 真实对象很难被创建。
- 真实对象的某些行为很难被触发。
- 真实对象实际上还不存在(和其他开发小组或和新的硬件打交道)等。
正是由于上面真实对象在测试的过程中存在的问题,在测试中广泛地采用mock测试来代替。
在单元测试上下文中,一个mock对象是指这样的一个对象——它能够用一些“虚构的占位符”功能来“模拟”实现一些对象接口。在测试过程中,这些虚构的占位符对象可用简单方式来模仿对于一个组件期望的行为和结果,从而让程序员专注于组件本身的彻底测试,而不用担心其他依赖性问题。
mock对象经常被用于单元测试。用mock对象来进行测试,就是在测试过程中,对于某些不容易构造(如HttpServletRequest必须在Servlet容器中才能构造出来)或不容易获取的比较复杂的对象(如JDBC中的ResultSet对象),用一个虚拟的对象( mock对象)来创建以便测试的测试方法。
mock最大的功能是把单元测试的耦合分解开,如果编写的代码对另一个类或接口有依赖,它能够模拟这些依赖,并验证所调用的依赖行为。
mock对象测试的关键步骤如下。
- 使用一个接口来描述这个对象。
- 在产品代码中实现这个接口。
- 在测试代码中实现这个接口。
- 在被测试代码中只是通过接口来引用对象,所以它不知道这个引用的对象是真实对象,还是mock对象。
目前,在Java阵营中主要的mock测试工具有Mockito、JMock、EasyMock 等。
5.mock与stub的区别
mock和 stub都是为了替换外部依赖对象,mock不是stub,两者有以下区别。
·前者称为mockist TDD,而后者一般称为classic TDD。
·前者是基于行为的验证(Behavior Verification ),后者是基于状态的验证(State Verification )。
·前者使用的是模拟的对象,而后者使用的是真实的对象。
现在通过一个例子来看看mock与 stub之间的区别。假如程序员要给发送mail的行为做一个测试,就可以像下面这样写一个简单的stub。
//待测试的接口
public interface Mailservice(){
public void send(Message msg);
}
/lstub测试类
public class MailServiceStub implements MailService i
private List<Message>messages = new ArrayList<Message>();
public void send (Message msg){
messages.add (msg);
}
public int numberSent( {
return messages.size();
}
}
}
也可以像下面这样在stub 上使用状态验证的测试方法。
public class orserStateTester{
Order order = new Order(TALISKER, 51);
MailServiceStub mailer = new MailserviceStub();
order.setMailer(mailer);
order.fill (warehouse);
//通过发送的消息数来验证
assertEquals(1 , mailer.numberSent();}
}
当然这是一个非常简单的测试,只会发送一条message。在这里程序员还没有测试它是否会发送给正确的人员或内容是否正确。
如果使用mock,那么这个测试看起来就不太一样了。
lass OrderInteractionTester. ..
public void testorderSendsMail工fUnFilled() {
Order order =new Order (TALISKER ,51);
Mock warehouse = mock(Warehouse.class);
Mock mailer = mock(MailService.class);
order.setMailer((Mailservice)mailer.proxy());
order.expects(once()).method ("hasInventory").withAnyArgument()
.will(returnvalue(false));
order.fill((Warehouse) warehouse.proxy()
}
在这两个例子中,使用了stub和mock来代替真实的MailService对象。所不同的是,stub使用的是状态确认的方法,而mock使用的是行为确认的方法。
想要在stub中使用状态确认,需要在stub中增加额外的方法来协助验证。因此stub实现了MailService但是增加了额外的测试方法。
微服务的集成测试
集成测试也称组装测试或联合测试,可以说是单元测试的逻辑扩展。它最简单的形式是把两个已经测试过的单元组合成一个组件,测试它们之间的接口。从使用的基本技术上来讲,集成测试与单元测试在很多方面都很相似。程序员可以使用相同的测试运行器和构建系统的支持。集成测试和单元测试一个比较大的区别在于,集成测试使用了相对较少的mock。
例如,在涉及数据访问层的测试时,单元测试会简单地模拟从后端数据库返回的数据。而集成测试时,测试过程中则会采用一个真实的数据库。数据库是一个需要测试资源类型及能暴露问题的极好的例子。
在微服务架构的集成测试中,程序员更加关注的是服务测试。
1.服务接口
在微服务的架构中,服务接口大多以RESTfulAPI的形式加以暴露。REST是面向资源的,使用HTTP协议来完成相关通信,其主要的数据交换格式为JSON,当然也可以是XML、HTML、二进制文件等多媒体类型。资源的操作包括获取、创建、修改和删除资源,它们都可以用HTTP协议的GET、POST、PUT和DELETE方法来映射相关的操作。
在进行服务测试时,如果只想对单个服务功能进行测试,那么为了对其他相关的服务进行隔离,则需要给所有的外部服务合作者进行打桩。每一个下游合作者都需要一个打桩服务,然后在进行服务测试的时候启动它们,并确保它们是正常运行的。程序员还需要对被测试服务进行配置,保证能够在测试过程中连接到这些打桩服务。同时,为了模仿真实的服务,程序员还需要配置打桩服务,为被测试服务的请求发回响应。
下面是一个采用Spring 框架实现的关于“用户车辆信息”测试接口的例子。
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.request.MockMvc
RequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvc
ResultMatchers.*;
@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyControllerTests{
@Autowired
private MockMvc mvc;
@MockBean
private UserVehicleService userVehicleService;
@Test
public void testExample( throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("BMW","X7"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_
PLAIN))
.andExpect(status().isok()).andExpect(content().
string("BMW x7"));
)
}
}
在该测试中,程序员用mock模拟了/sboot/vehicle接口的数据VehicleDetails("BMW","X7"),并通过MockMvc来进行测试结果的判断。
2.客户端
有非常多的客户端可以用于测试RESTful服务。可以直接通过浏览器来进行测试,如在本书前面介绍过的RESTClient、Postman等。很多应用框架本身提供了用于测试RESTful API的类库,如Java平台的像Spring的RestTemplate 和像Jersey的Client API等,.NET平台的RestSharp ( http:1restsharp.org)等。也有一些独立安装的REST测试软件,如SoapUI ( ttps:/www.soapui.org ),当然最简洁的方式莫过于使用cURL在命令行中进行测试。
下面是一个测试Elasticsearch是否启动成功的例子,可以在终端直接使用cURL来执行以下操作。
scurl 'http://localhost:9200/?pretty'
cURL提供了一种将请求提交到Elasticsearch的便捷方式,然后可以在终端看到与下面类似的响应。
"cluster name": "elasticsearch",
"cluster uuid" :"uqcQAMTtTIO6CanROYgveQ",
"version":{
"number": "5.5.0",
"build_hash":"260387d" ,
"build_date":"2017-06-30T23:16:05.735Z"",
"build_snapshot" :false,
"lucene version":"6.6.O"
},
"tagline":"You Know, for Search"
}
微服务的系统测试
引入微服务架构之后,随着微服务数量的增多,测试用例也随之增多,测试工作也越来越依赖于测试的自动化。Maven或Gradle等构建工具,都会将测试纳入其生命周期内,所以,只要写好相关的单元测试用例,单元测试及集成测试就能在构建过程中自动执行,构建完成之后,也可以马上看到测试报告。
在系统测试阶段,除了自动化测试外,手工测试仍然是无法避免的。Docker等容器为自动化提供了基础设施,也为手工测试带来了新的变革。
在基于容器的持续部署流程中,软件会经历最终被打包成容器镜像,从而可以部署到任意环境而无须担心工作变量不一致所带来的问题。进入部署阶段意味着集成测试及单元测试都已经通过了。
但这显然并不是测试的全部,很多测试必须要在上线部署后才能进行,如一些非功能性的需求。
同时,用户对于需求的期望是否与最初的设计相符,这个也必须要等到产品上线后才能验证。所以,上线后的测试工作仍然是非常重要的。
1.冒烟测试
所谓冒烟测试,是指对一个新编译的软件版本在需要进行正式测试前,为了确认软件基本功能是否正常而进行的测试。软件经过冒烟测试之后,才会进行后续的正式测试工作。冒烟测试的执行者往往是版本编译人员。
由于冒烟测试耗时短,并且能够验证软件大部分主要的功能,因此在进行CI/CD每日构建过程中,都会执行冒烟测试。
⒉蓝绿部署
蓝绿部署通过部署新旧两套版本来降低发布新版本的风险。其原理是,当部署新版本后(绿部署),老版本(蓝部署)仍然需要保持在生产环境中可用一段时间。如果新版本上线,测试没有问题后,那么所有的生产负荷就会从旧版本切换到新版本中。
以下是一个蓝绿部署的例子。其中,vl代表的是服务的旧版本(蓝色),v2代表的是新版本(绿色),如图4-2所示。
这里面有以下几个注意事项。
- 蓝绿两个部署环境是一致的,并且两者应该是完全隔离的(可以是不同的主机或不同的容器)。
- 蓝绿环境两者之间有一个类似于切换器的装置用于流量的切换,如可以是负载均衡器、反向代理或路由器。
- 新版本(绿部署)测试失败后,可以马上回溯到旧版本。
- 蓝绿部署经常与冒烟测试结合使用。
- 实施蓝绿部署,整个过程是自动化处理的,用户并不会感觉到任何宕机或服务重启。
3.A/B测试
A/B测试是一种新兴的软件测试方法。A/B测试本质上是将软件分成A、B两个不同的版本来进行分离实验。AB测试的目的在于通过科学的实验设计、采样样本、流量分割与小流量测试等方式来获得具有代表性的实验结论,并确保该结论在推广到全部流量之前是可信赖的。例如,在经过一段时间的测试后,实验结论显示,B版本的用户认可度较高,于是,线上系统就可以更新到B版本上来。
4.金丝雀发布
金丝雀发布是增量发布的一种类型,它的执行方式是在原有软件生产版本可用的情况下,同时部署一个新的版本。这样,部分生产流量就会引流到新部署的版本,从而来验证系统是否按照预期的内容执行。这些预期的内容可以是功能性的需求,也可以是非功能性的需求。例如,程序员可以验证新部署的服务的请求响应时间是否在1秒以内。
如果新版本没有达到预期的效果,那么可以迅速回溯到旧版本上去。如果达到了预期的效果,那么可以将生产流量更多地引流到新版本上去。
金丝雀发布与A/B测试非常类似,两者往往结合使用。而与蓝绿部署的差异在于,金丝雀发布新旧版本并存的时间更长久一些。
本篇内容给大家介绍的是微服务架构的单元测试、集成测试和系统测试三个方面。
- 下篇文章给大家介绍微服务的协调者——Spring Cloud的内容;
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!!
本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。
上一篇: 单元测试的必要性?一篇谈论单元测试的文章
推荐阅读
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
如何进行微服务的单元测试、集成测试和系统测试?
-
什么是可用性测试?有效性(Effectiveness)-- 用户完成特定任务和实现特定目标的正确性和完整性程度;效率(Efficiency)-- 用户完成任务的正确性和完整性程度与所用资源(如时间)之比;满意度(Satisfaction)-- 用户在使用产品时的主观满意度和接受程度。 2.如何获得可用性? 可以参考以下原则:Gould、Boies 和 Lewis(1991 年)为以用户为中心的设计定义了 4 个重要原则: 早期以用户为中心:设计者应在设计过程的早期就努力了解用户的需求。 综合设计:设计的所有方面都应同步发展,而不是按顺序进行。使产品的内部设计始终与用户界面的需求保持一致。 早期和持续测试:当今唯一可行的软件测试方法是经验主义方法,即如果实际用户认为设计可行,该设计就是可行的。通过在整个开发过程中引入可用性测试,用户就有机会在产品推出之前对设计提出反馈意见。 迭代设计:大问题往往掩盖了小问题的存在。设计人员和开发人员应在整个测试过程中对设计进行迭代。 3...什么是可用性测试? 可用性测试是根据可用性标准对图形用户界面进行的系统评估。 可用性测试是衡量用户与系统(网站、软件应用程序、移动技术或任何用户操作设备)交互时的体验质量。4.如何进行可用性测试? l 实验室实验
-
纯干货分享 | 研发效能提升——敏捷需求篇-而敏捷需求是提升效能的方式中不可或缺的模块之一。 云智慧的敏捷教练——Iris Xu近期在公司做了一场分享,主题为「敏捷需求挖掘和组织方法,交付更高业务价值的产品」。Iris具有丰富的团队敏捷转型实施经验,完成了企业多个团队从传统模式到敏捷转型的落地和实施,积淀了很多的经验。 这次分享主要包含以下2个部分: 第一部分是用户影响地图 第二部分是事件驱动的业务分析Event driven business analysis(以下简称EDBA) 用户影响地图,是一种从业务目标到产品需求映射的需求挖掘和组织的方法。 在软件开发过程中可能会遇到一些问题,比如大家使用不同的业务语言、技术语言,造成角色间的沟通阻碍,还会导致一些问题,比如需求误解、需求传递错误等;这会直接导致产品的功能需求和要实现的业务目标不是映射关系。 但在交付期间,研发人员必须要将这些需求实现交付,他们实则并不清楚这些功能需求产生的原因是什么、要解决客户的哪些痛点。研发人员往往只是拿到了解决方案,需要把它实现,但没有和业务侧一起去思考解决方案是否正确,能否真正的帮助客户解决问题。而用户影响地图通常是能够连接业务目标和产品功能的一种手段。 我们在每次迭代里加入的假设,也就是功能需求。首先把它先实现,再逐步去验证我们每一个小目标是否已经实现,再看下一个目标要是什么。那影响地图就是在这个过程中帮我们不断地去梳理目标和功能之间的关系。 我们在软件开发中可能存在的一些问题 针对这些问题,我们如何避免?先简单介绍做敏捷转型的常规思路: 先做团队级的敏捷,首先把产品、开发、测试人员,还有一些更后端的人员比如交互运维的同学放在一起,组成一个特训团队做交付。这个团队要包含交付过程中所涉及的所有角色。 接着业务敏捷要打通整个业务环节和研发侧的一个交付。上图中可以看到在敏捷中需求是分层管理的,第一层是业务需求,在这个层级是以用户目标和业务目标作为输入进行规划,同时需要去考虑客户的诉求。业务人员通过获取到的业务需求,进一步的和团队一起将其分解为产品需求。所以业务需求其实是我们真正去发布和运营的单元,它可以被独立发布到我们的生产环境上。我们的产品需求其实就是产品的具体功能,它是我们集成和测试的对象,也就是我们最终去部署到系统上的一个基本单元。产品需求再到了我们的开发团队,映射到迭代计划会上要把它分解为相应的技术任务,包括我们平时所说的比如一些前端的开发、后端的开发、测试都是相应的技术任务。所以业务敏捷要达到的目标是需要去持续顺畅高质量的交付业务价值。 将这几个点串起来,形成金字塔结构。最上层我们会把业务目标放在整个金字塔的塔尖。这个业务目标是通过用户的目标以及北极星指标确立的。确认业务目标后再去梳理相应的业务流程,最后生产。另外产品需求包含了操作流程和业务规则,具需求交付时间、工程时间以及我们的一些质量标准的要求。 谈到用户影响的地图,在敏捷江湖上其实有一个传说,大家都有一个说法叫做敏捷需求的“任督二脉”。用户影响地图其实就是任脉,在黑客马拉松上用过的用户故事地图其实叫督脉。所以说用户影响地图是在用户故事地图之前,先帮我们去梳理出我们要做哪些东西。当我们真正识别出我们要实现的业务活动之后,用户故事地图才去梳理我们整个的业务工作流,以及每个工作流节点下所要包含的具体功能和用户故事。所以说用户影响地图需要解决的问题,我们包括以下这些: 首先是范围蔓延,我们在整张地图上,功能和对应的业务目标是要去有一个映射的。这就避免了一些在我们比如有很多干系人参与的会议上,那大家都有不同想法些立场,会提出很多需求(正确以及错误的需求)。这个时候我们会依据目标去看这些需求是否真的是会影响我们的目标。 这里提到的错误需求,比如是利益相关的人提出的、客户认为产品应该有的、某个产品经理需求分析师认为可以有的....但是这些功能在用户影响地图中匹配不到对应目标的话,就需要降低优先级或弃掉。另外,通常我们去制定解决方案的时候,会考虑较完美的实现,导致解决方案括很多的功能。这个时候关键目标至关重要,会帮助我们梳理筛选、确定优先级。 看一下用户影响到地图概貌 总共分为一个三层的结构: 第一层why,你的业务目标哪个是最重要的,为什么?涉及到的角色有哪些? 第二层how ,怎样产生影响?影响用户角色什么样的行为? (不需要去列出所有的影响,基于业务目标) 第三层what,最关键的是在梳理需求时不需一次把所有细节想全,这通常团队中经常遇到的问题。 我们用这个例子来看一下 这是一个客服中心的影响地图,业务目标是 3个月内不增加客服人数的前提下能支持1.5倍的用户数。此业务目标设定是符合 smart 原则的,specific非常的具体,miserable 是可以衡量的,action reoriented是面向活动的, real list 也是很实际的。 量化的目标会指引我们接下来的行动,梳理一个业务目标,尽量去量化,比如 :我们通过打造一条什么样的流水线,能够提高整个部署的效率,时间是原来的 1/2 。这样才是一个能量化的有意义的目标。 回到这幅图, how 层级识别出来的内容,客服角色:想要对它施加的影响,把客户引导到论坛上,帮助客户更容易的跟踪问题,更快速的去定位问题。初级用户:方论坛上找到问题。高级用户:在论坛上回答问题。通过我们这些用户角色,进行活动,完成在不增加客户客服人数的前提下支持更多的用户数量。 最后一个层级,才是我们日常接触比较多的真正的功能的特性和需求,比如引导到客户到论坛上,其实这个产品就需要有一个常见问题的论坛的链接。这个层次需要我们团队进一步地在交付,在每个迭代之前做进一步的梳理,细化成相应的用户故事。 这个是云智慧团队中,自己做的影响地图的范例,可以看下整个的层级结构。序号表示优先级。 那我们用户影响地图可以总结为:
-
单元测试、集成测试和系统测试的区别
-
软件测试的四个发展阶段【单元测试、集成测试、系统测试和验收测试】