软件可测试性是指通过测试 (通常是基于运行的测试) 揭示软件缺陷的容易程度. 在开发设计良好的系统的成本中, 至少有 40% 是用在了测试上. 如果我们能够降低此成本, 那带回的回报将是巨大的. 当然, 如果要对系统进行正确的测试, 必须能够 "控制" 每个组件的内部状态及其输入, 然后 "观察" 其输出. 这通常通过使用 "测试工具" 进行, 这是一种专门设计的软件, 用于执行所测试的软件. 这可能会如同在各种接口上回放已记录的数据一样简单, 也可能会像测试发动机的燃烧室一样复杂.
质量属性的第五大战术是可测试性战术. 什么是可测试性战术, 顾名思义, 测试就是为了发现错误, 那么可测试性战术的目标是允许在完成软件开发的一个增量后, 轻松地对软件进行测试. 可测试性战术的分类可以由下图所示:
1. 记录 / 回放(Record/playback ): 记录 / 回放是指将捕获跨接口的信息, 并将其作为测试专用软件的输入.
使用命令模式把一个请求或者操作封装到一个对象中, 把发出命令的责任和执行命令的责任分割开, 委派给不同的对象, 可降低行为请求者与行为实现者之间耦合度. 在这里, 我们通过维护 undo 和 redo 两个盛放 Command 的栈 (用 List 实现), 首次执行一个 Command 时, 执行 execute() 并将其放入 undo 栈内, 同时要清空 redo 栈; 当执行撤销操作时把 undo 栈内最上面一个 Command 拿出来执行 undo(), 然后将其放入 redo 栈内; 执行重做操作时把 redo 栈内最上面一个 Command 拿出来执行 execute(), 然后将其放入 undo 栈内.
当点击按钮执行操作时, 可在其 ActionListener 内执行 commandManager.executeCommand(newXXXCommand()); 把命令加入栈中.
- public class CommandManager {
- private List undoList = new ArrayList();
- private List redoList = new ArrayList();
- // 可撤销的步数,-1 时无限步
- private int undoCount = -1;
- public CommandManager() {
- // 可通过配置文件配置撤销步数
- undoCount = 5;
- }
- /**
- * 执行新操作
- */
- public void executeCommand(Command cmd) {
- // 执行操作
- cmd.execute();
- undoList.add(cmd);
- // 保留最近 undoCount 次操作, 删除最早操作
- if (undoCount != -1 && undoList.size()> undoCount) {
- undoList.remove(0);
- }
- // 执行新操作后清空 redoList, 因为这些操作不能恢复了
- redoList.clear();
- }
- /**
- * 执行撤销操作
- */
- public void undo() {
- if (undoList.size() <= 0) {
- return;
- }
- Command cmd = ((Command)(undoList.get(undoList.size() - 1)));
- cmd.undo();
- undoList.remove(cmd);
- redoList.add(cmd);
- }
- /**
- * 执行重做
- */
- public void redo() {
- if (redoList.size() <= 0) {
- return;
- }
- Command cmd = ((Command)(redoList.get(redoList.size() - 1)));
- cmd.execute();
- redoList.remove(cmd);
- undoList.add(cmd);
- }
2. 将接口与实现分离(Separate interface from implementation )
将接口与实现分离指的就是将接口与实现分离允许实现的代替. 占位实现允许在缺少被占位组件时, 对系统的剩余部分进行测试.
在上面的例子中, 我们使用的是命令模式, 当然不可避免的要使用接口来进行定义. 因此就会使用分离的格式进行测试.
- public interface Command {
- public void execute(); // 执行命令和重做
- public void undo(); // 执行撤销操作
- }
如果缺少接口类的调用, 那就会在代码修改时发生大量的变动, 使得测试工作也难以进行下去.
3. 特化访问路线 / 接口
特化的接口可以独立于程序正常运行, 即设计独立的接口仅供测试使用.
比如在 python web 开发的 Django 框架中, 我们通过专门的数据库连接来获取到我们的数据库数据, 他并不是在程序运行的过程中直接显示的, 而是在刚开始进行框架设计的时候就进行了数据的加载. 通过更改配置文件, 来达到获取数据的目的.
在 settings 中创建数据库连接, 然后执行脚本, 就可以得到我们的数据.
- """
- Django settings for django_demo_00 project.
- Generated by 'django-admin startproject' using Django 3.0.3.
- For more information on this file, see
- https://docs.djangoproject.com/en/3.0/topics/settings/
- For the full list of settings and their values, see
- https://docs.djangoproject.com/en/3.0/ref/settings/
- """
- import os
- # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
- BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- # Quick-start development settings - unsuitable for production
- # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
- # SECURITY WARNING: keep the secret key used in production secret!
- SECRET_KEY = '!fo8_1bnoyif_rzsg*y4w&b8g4a5r&2pv9j0c-so-2ncrhet_2'
- # SECURITY WARNING: don't run with debug turned on in production!
- DEBUG = True
- ALLOWED_HOSTS = []
- # Application definition
- INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'demo_00_app',
- ]
- MIDDLEWARE = [
- 'django.middleware.security.SecurityMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
- ]
- ROOT_URLCONF = 'django_demo_00.urls'
- TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- ],
- },
- },
- ]
- WSGI_APPLICATION = 'django_demo_00.wsgi.application'
- # Database
- # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.mysql',
- 'NAME': 'db_pymysql',
- 'USER':'root',
- 'PASSWORD':'20173673',
- 'HOST':'localhost',
- 'PORT':'3306'
- }
- }
- # Password validation
- # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
- AUTH_PASSWORD_VALIDATORS = [
- {
- 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
- },
- ]
- # Internationalization
- # https://docs.djangoproject.com/en/3.0/topics/i18n/
- LANGUAGE_CODE = 'en-us'
- TIME_ZONE = 'UTC'
- USE_I18N = True
- USE_L10N = True
- USE_TZ = True
- # Static files (CSS, JavaScript, Images)
- # https://docs.djangoproject.com/en/3.0/howto/static-files/
- STATIC_URL = '/static/'
- View Code
在 settings 中, 有许多的事件都是通过修改配置文件进行的, Django 也是通过将需要的接口进行特化, 来实现相应功能的实现.
4. 内部监视器(Built-in monitors )
内部检测器指的是组件可以维持状态, 性能负载, 容量, 安全性或其他可通过接口访问的信息. 当监视状态被激活时可以记录事件. 说到这里, 就不得不说谷歌浏览器的开发者模式了.
Google 通过对网页的传递信息进行监听, 进而获得到了请求于传输相应等内容, 这在我们做 spider 分析的时候是至关重要的, 同时, 对于前端的开发, 我们也可以通过他进行前端模块的展示, 如果是 Ajax 进行加载的话, 就是通过 NetWork 中的 XHR 进行查看, 加载出的数据也就一目了然了.
来源: http://www.bubuko.com/infodetail-3447712.html