软件测试是一个工程

属于软件质量控制、质量保证的一部分。由于软件的复杂性,软件测试需要分出层次来,并由不同的人完成不同的测试任务,在不同层面不同维度和角度保证软件按照设计和预期运行。

软件测试并不是银弹,不能保证软件100%没有问题。但是组织良好的软件测试工程,相比随意和混乱的测试甚至不测试,能够以比较低的成本发现大部分的软件缺陷,保证软件质量。

软件测试按照不同的层级,分为:单元测试, 系统(功能)测试, UAT测试, 生产测试, 回归测试

单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。这部分测试过程由负责开发相应软件模块单元的开发人员执行,一般软件都会要求在源代码层面,单元测试能够测试(覆盖)到大部分的软件源代码。比如Salesforce要求部署到生产环境的代码必须有75%的代码覆盖率。

系统(功能)测试

一般会把功能测试和系统测试分开,但是实际上这些测试过程都由软件测试工程师执行。功能测试偏向每个功能运行的正确和准确,是从细节的角度解读测试;而系统测试则偏向整个软件系统的整体运行,包含一些非功能性测试(例如响应时间、安全等),是从整体的角度解读测试。但是不论功能测试或者系统测试,都是从逻辑的层面确保软件的每个功能和整个软件系统的正常运行。

UAT测试

UAT测试,即用户认可测试,必须由将使用软件的最终用户进行。测试将模拟业务中的实际事件和日常使用情况,因此您可以确认该软件是否满足用户的需求。UAT测试是从业务的层面出发,保障系统的满足实际业务需求。

生产测试

在生产环境中重复进行系统(功能)测试的一部分测试,这将确认代码和配置是否已从测试或沙盒环境正确转移到生产环境中中。建议在此步骤后重复进行 UAT 测试。

回归测试

一旦发布并安装了新的软件更新,或者检测到并修复了错误,都应该进行回归测试。即从头到尾对受升级或者修复错误影响的软件部分从头到位测试一遍(回归)。它确保所有以前的使用和过程在进行更改后仍然正常有效地运行。

可以看到,不同层次和类别的测试,有不同的角度和目的,也由不同的人员执行。让软件开发人员或者最终用户直接完成所有的测试工作,都是不可靠的。因为他们掌握的知识技能和他们的背景以及经验,不足以应对整个复杂的分层次的软件测试工程。

2GP Managed Package

Salesforce 第二代管控包(Second-Generation Managed Packages)是Salesforce最新推广的最佳实践。通过Salesforce CLI,我们可以很方便的制作和部署第二代管控包。本文只是简略的将核心步骤展示出来:

涉及的各种环境

整个第二代管控包需要用到4类org:

  1. Dev Hub Org:承载所有二代包。可以将各个命名空间的二代包链接到这个org。最好是PBO
  2. Namespace Org:一般是Developer org,在其中申请相应的命名空间,由于命名空间一旦申请便与该org永久绑定且不可修改,申请时请慎重。
  3. Scratch Orgs:在开发测试中使用。
  4. Production Orgs:按照和使用包的生产环境。

2GP Packages.drawio.svg
相关org关系示意图。

10步完成制作

  1. 创建一个 SFDX 项目

    sfdx force:project:create --outputdir expense-manager-workspace --projectname expenser-app
  2. 授权Dev Hub环境,该环境必须启用Dev Hub功能和未锁定包和第二代管控包功能

    sfdx auth:web:login -d -a devHub
  3. 创建一个草稿环境(scratch org)并在其中开发包

    sfdx force:org:create -f config/project-scratch-def.json -u scratchOrg1
  4. 保证所有要打包的组件都已经在当前的项目文件夹内
  5. sfdx-project.json文件中,使用命名空间属性指定命名空间。例如:“namespace”:“exp-mgr”
  6. 从 SFDX 项目文件夹,直接创建管控包:

    sfdx force:package:create --name "Expense Manager" --path force-app --packagetype Managed
  7. 检查项目文件夹中的sfdx-project.json文件,CLI 会自动更新项目文件,使其包含上一步创建的包的信息:

    {
    "packageDirectories": [
       {
          "path": "force-app",
          "default": true,
          "package": "Expense Manager",
          "versionName": "ver 0.1",
          "versionNumber": "0.1.0.NEXT"
       }
    ],
    "namespace": "exp-mgr",
    "sfdcLoginUrl": "https://login.salesforce.com",
    "sourceApiVersion": "51.0",
    "packageAliases": {
       "Expense Manager": "0Hoxxx"
    }
    }
  8. 创建一个包的版本,Salesforce CLI会自动处理包的版本号等

    sfdx force:package:version:create --package "Expense Manager" --installationkey test1234 --wait 10
  9. 在另一个创建好的草稿环境中,安装并测试这个版本的包:

    sfdx force:package:install --package "Expense [email protected]" --targetusername MyTestOrg1 
    --installationkey test1234 --wait 10 --publishwait 10
  10. 安装包后,打开scratch org查看包:

    sfdx force:org:open --targetusername MyTestOrg1
\frac{a}{b^2}

参考:

  1. Salesforce DX Developer Guide
  2. Link a Namespace to a Dev Hub Org
  3. Create and Register Your Namespace for Second-Generation Managed Packages
  4. Workflow for Second-Generation Managed Packages

云服务器中通过Docker镜像的方式使用Mysql数据库,数据安全考量定期备份数据库到阿里云OSS中

本文主要实现在阿里云ECS服务器中,通过脚本的方式实现将Docker中的Mysql数据库备份到阿里云OSS中。其他云服务商和其他环境的MySQL也可以使用类似的方式。具体方式不再赘述。

环境和工具

  1. 阿里云ECS服务器,安装Ubuntu或任何带有定时任务cron的Linux操作系统
  2. 阿里云OSS bucket和相应访问的账户
  3. 阿里云OSS命令行工具ossutil,可以到这里下载或查看详情
  4. MySQL镜像

具体步骤

开通OSS和相应子账号

  1. 进入阿里云OSS(对象存储)控制台,如果没有开通OSS服务可能会提示权限和开通确认。
  2. 创建bucket/存储桶,输入名字,比如xxxxbackup,记住这个名字以及界面中出现的Endpoint(地域节点),后续会用到。
    WX20220720-115411.png
  3. 创建一个有API的阿里云子账号,并赋予OSS读写权限。记住该账号的API和Secret,后续会用到。帮助文档
    WX20220720-115547.png

下载OSS命令行工具ossutil到本地系统

  1. 通过wget https://gosspublic.alicdn.com/ossutil/1.7.13/ossutil64下载到本地。这里是64位操作系统,32位可以去下载界面查看对应的下载地址。
  2. 增加运行权限:chmod +x ossutil64
  3. 移动到Path中:sudo mv ossutil64 /bin/

编写脚本

这里需要注意docker容器的名称,容器中应该有MYSQL用户名和密码的环境变量;示例中使用的是root作为用户名;另外备份临时文件夹也需要提前使用mkdir建好

脚本内容示例:

#!/bin/sh 

mysql_dump_path=备份文件临时目录,如/var/dbbackup/ 

#oss-config 
oss_endpoint="阿里云OSS Endpoint" 
oss_bucket="阿里云OSS bucket名称" 
oss_accesskeyid="子账号AccessKeyId" 
oss_accesskeysecret="子账号 AccessKey Secret" 
backup_name=`date +%Y%m%d%H%M%S`
cd ${mysql_dump_path} 

# 使用 mysqldump 备份整个数据库到临时文件夹中
# 注意docker修改docker镜像名称,这里是some-mysql
docker exec some-mysql sh -c 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --all-databases' > ${backup_name}.sql

# 打包/pack 
tar zcf ${backup_name}.tar.gz ${backup_name}.sql 
rm -f ${backup_name}.sql 

# 备份到OSS
ossutil64 cp ${backup_name}.tar.gz oss://${oss_bucket}/mysql/backup/${backup_name}.tar.gz -f -e ${oss_endpoint} -i ${oss_accesskeyid} -k ${oss_accesskeysecret} 
rm -f ${backup_name}.tar.gz 
echo "备份完成"

将脚本保存至任意一个不错的位置,比如/var/backup/dbbackup.sh,赋予可执行权限:sudo chmod +x /var/backup/dbbackup.sh

试着运行一下脚本文件sudo /var/backup/dbbackup.sh,再去oss控制台该bucket下-文件管理处查看是否有备份文件存入。如果一切没有问题,则就可以加入cron了。

加入cron计划任务

注:如果脚本位置和临时备份文件夹位置是当前用户无法直接编辑的,则应使用一下方法,在系统级别运行计划任务;用户级别会因为权限问题出错

使用你喜欢的编辑器打开/etc/crontab文件,并在文件末尾加上这行:

23 2 * * * root /var/backup/dbbackup.sh

这表示在每天的02:23:00运行我们的备份脚本。

重新启动cron计划任务:sudo service cron reload

在次日2:23分之后检查OSS控制台后台,即可发现整个数据库已经备份到阿里云OSS。

参考

  1. 使用ossutil定时备份自建mysql数据库到阿里云OSS
  2. Cron介绍
  3. docker hub: mysql

问题和原因

jupyter notebook通过nbconvert调用Latex导出PDF,由于nvconvert中转换模版中并不包含中文支持的package申明,导致Latex渲染时无法识别中文字符和对应的字体。出现类似:

LaTeX Error: Unicode character 正 (U+6B63) not set up for use with LaTeX.

的报错。导出的PDF文件中,所有中文字符都显示为空白。

解决方案

有两种方法可以解决:

  1. 先从Notebook导出为Latex,再使用如TexShop等工具打开Latex文件并添加中文支持,之后导出
  2. 修改nbconvert的模版,直接添加中文支持,这样即可直接导出PDF

这里说第二种办法:

首先通过jupyter --paths获得Jupyter相关路径,

% jupyter --paths

输出类似:

config:
    /Users/xxx/.jupyter
    /Users/xxx/custom_path/venv/etc/jupyter
    /usr/local/etc/jupyter
    /etc/jupyter
data:
    /Users/xxx/Library/Jupyter
    /Users/xxx/custom_path/venv/share/jupyter
    /usr/local/share/jupyter
    /usr/share/jupyter
runtime:
    /Users/xxx/Library/Jupyter/runtime

找到...share/jupyter文件夹所在位置,并定位到...share/jupyter/nbconvert/templates/latex文件夹,里面有nbconvert转换LaTex模版,
nvconvert-latex.png
通过修改base.tex.j2模版文件,添加xeCJK包申明和相关字体即可影响所有相关模版:

    \usepackage{xeCJK}
    \setCJKmainfont{STSong}

添加完成后,模版文件应类似:

((*- block header -*))
    ((* block docclass *))\documentclass[11pt]{article}((* endblock docclass *))

    ((* block packages *))
    \usepackage{xeCJK}
    \setCJKmainfont{STSong}
    \usepackage{iftex}
    ...

注意,字体部分可以通过Mac的字体书(Font Book)找到合适的中文字体名称,不一定非得使用宋体(STSong)。另外除了主要字体,也可以定义其他情况的字体,若加粗和倾斜时应用的字体。

相关文章

github:jupyter/nbconvert
Mac环境下jupyter notebook导出PDF显示中文的解决方案 (nbconvert 6, python 3.9)
convert notebook (contains Chinese words) to PDF successfully but those Chinese words are missing

通过在.Net Core应用中运行Python脚本,可以非常方便的进行某些功能的处理。特别是考虑到Python是解释型语言,不需要像.Net 那样编译再部署。

通过使用NuGet中的IronPythonIronPython.StdLib:

public class PythonScript
{
    private ScriptEngine _engine;

    public PythonScript()
    {
        _engine = Python.CreateEngine();
    }

    public TResult RunFromString<TResult>(string code, string variableName)
    {
        // for easier debugging write it out to a file and call: _engine.CreateScriptSourceFromFile(filePath);
        ScriptSource source = _engine.CreateScriptSourceFromString(code, SourceCodeKind.Statements);
        CompiledCode cc = source.Compile();

        ScriptScope scope = _engine.CreateScope();
        cc.Execute(scope);

        return scope.GetVariable<TResult>(variableName);
    }
}

然后使用运行脚本:

var py = new PythonScript();
var result = py.RunFromString<int>("d = 8", "d");
Console.WriteLine(result);

原生的ProcessProcessStartInfo (个人实践出来的)

注意,需要通过执行含有Python可执行文件和参数的shell脚本来实现执行Python脚本, 有点绕,具体就是:

1, 创建一个run.batWindows系统:

C:\YOUR_PYTHON_PATH\python.exe %*

2, 创建一个run.sh文件给LInux系统:

#!/bin/bash
/usr/bin/python3 "$@"

3, 使用Process and ProcessStartInfo 来运行脚本:

string fileName = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
    fileName = "path_to_bat/run.bat"
}
else
{
    fileName = "path_to_bat/run.sh"
}

ProcessStartInfo start = new ProcessStartInfo
{
    FileName = fileName,
    Arguments = string.Format("\"{0}\" \"{1}\"", script, args),
    UseShellExecute = false,
    CreateNoWindow = true,
    RedirectStandardOutput = true,
    RedirectStandardError = true
};
using Process process = Process.Start(start);

变量script指代需要执行的Python脚本所在位置,变量args指代脚本需要的参数,若有多个参数,酌情修改程序片段。

参考

  1. How to use Python in .NET-Core application?
  2. How to run python script from C# code by using command