Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu.Wang 2019-01-26 21:56:13 +08:00
commit 589a36a5fa
4 changed files with 200 additions and 177 deletions

View File

@ -0,0 +1,67 @@
Fedora 28 服务器版的模块化
========
![](https://fedoramagazine.org/wp-content/uploads/2018/05/f28-server-modularity-1024x433.jpg)
### 什么是模块化
所有开源发行版都面临的一个经典难题是“太快/太慢”的问题。用户安装操作系统是为了能够使用其应用程序。像 Fedora 这样的全面的发行版在大量可用软件方面有其优势和劣势。虽然有用户想要的软件包,但可能无法使用其所需的版本。以下是<ruby>模块化<rt>Modularity</rt></ruby>如何帮助解决该问题。
对于某些用户Fedora 有时升级得太快。其快速发布周期以及尽可能提供最新稳定软件的愿望可能导致与应用程序的兼容性下降。如果因为 Fedora 将 Web 框架升级为不兼容的版本而导致用户无法运行 Web 应用程序则会非常令人沮丧。对“太快”问题的经典回答是“Fedora 应该有一个 LTS 版本。”然而,这种方法只能解决问题的一半,并使这个难题的另一面变得更糟。
有时候 Fedora 对某些用户而言又升级速度太慢。例如Fedora 的发布可能与其它想要的软件的发布时间不匹配。一旦 Fedora 版本宣布稳定,打包者必须遵守 [稳定更新政策][1] 并且不能在系统中引入不兼容的更改。
Fedora 的模块化从两个方面解决了这个问题。Fedora 仍将根据其传统政策发布标准版本。但是,它还将提供一组模块给出流行软件的限定替代版本。那些处于“太快”阵营的人仍然可以享受 Fedora 的新内核和其它通用平台增强功能。此外,他们仍然可以访问支持其应用程序的旧框架或工具链。
此外,那些喜欢更新潮一些的用户可以访问比发布时更新的软件。
### 模块化不是什么?
模块化不是 <ruby>[软件集合][2]<rt>Software Collections</rt></ruby> 的直接替代品。这两种技术试图解决许多相同的问题,但有明显的差异。
软件集合可以在系统上并行安装不同版本的软件包。但是,它们的缺点是每份安装包都存在于文件系统上的它们自己的命名空间里面。此外,需要告诉每个依赖它们的应用程序在哪里找到它们。
使用模块化,系统上只存在一个版本的软件包,但用户可以选择哪个版本。优点是该版本位于系统的标准位置。该程序包不需要对依赖它的应用程序进行特殊更改。来自用户研究的反馈表明,大多数用户实际上并不依赖于并行安装。容器化和虚拟化解决了这个问题。
### 为什么不干脆使用容器化?
这是另一个常见问题。为什么用户在可以使用容器时还需要模块?答案是,人们仍然需要维护容器中的软件。 模块为那些用户不需要自己维护、更新和修补的容器提供预打包的内容。这就是 Fedora 如何利用发行版的传统价值并将其转移到新的容器化的世界。
以下是模块化如何为 Node.js 和 Review Board 的用户解决问题的示例。
### Node.js
许多读者可能熟悉 Node.js这是一个流行的服务器端 JavaScript 运行时环境。Node.js 采用偶数/奇数版本策略。它的社区支持偶数版本6.x、8.x、10.x 等)约 30 个月。同时,他们也支持奇数版本,基本上是 9 个月的开发者预览版。
由于这个周期的原因Fedora 在其稳定的仓库中只携带最新的偶数版本的 Node.js。它完全避免了奇数版本因为它们的生命周期比 Fedora 短,并且通常与 Fedora 发布周期不一致。对于一些希望获得最新和最大增强功能的 Fedora 用户来说,这并不合适。
由于模块化Fedora 28 不是提供了一个版本,而是提供了三个版本的 Node.js以满足开发人员和稳定部署的需求。Fedora 28 的传统仓库带有 Node.js 8.x。此版本是发布时最新的长期稳定版本。模块仓库默认情况下在 Fedora 28 Server 版本上可用)也使得更旧的 Node.js 6.x 版本和更新的 Node.js 9.x 开发版本可用。
另外Node.js 在 Fedora 28 之后几天发布了 10.x 上游版本。过去,想要部署该版本的用户必须等到 Fedora 29或者使用来自 Fedora 之外的源代码。但是再次感谢模块化Node.js 10.x 已经在 Fedora 28 的 Modular Updates-Testing 仓库中 [可用][3] 了。
### Review Board
Review Board 是一个流行的 Django 应用程序用于执行代码审查。Fedora 从 Fedora 13 到 Fedora 21 都包括了 Review Board。此时Fedora 转移到了 Django 1.7。由于 Django 数据库支持的向后兼容性在不断变化,而 Review Board 无法跟上。它在 RHEL / CentOS 7 的 EPEL 仓库中仍然存在,而仅仅是因为这些发行版的版本幸运地被冻结在 Django 1.6上。尽管如此,它在 Fedora 的时代显然已经过去了。
然而随着模块化的出现Fedora 能够再次将旧的 Django 作为非默认模块流发布。因此Review Board 已作为一个模块在 Fedora 上恢复了。Fedora 承载了来自上游的两个受支持的版本2.5.x 和 3.0.x。
### 组合在一起
Fedora 一直为用户提供非常广泛的软件使用。Fedora 模块化现在为他们所需的软件版本提供了更深入的选择。接下来的几年对于 Fedora 来说将是非常令人兴奋的,因为开发人员和用户可以以新的和令人兴奋的(或旧的和令人兴奋的)方式组合他们的软件。
------
via: https://fedoramagazine.org/working-modules-fedora-28/
作者:[Stephen Gallagher][a]
选题:[wxy](https://github.com/wxy)
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://fedoramagazine.org/author/sgallagh/
[1]: https://fedoraproject.org/wiki/Updates_Policy#Stable_Releases
[2]: https://www.softwarecollections.org/
[3]: https://bodhi.fedoraproject.org/updates/FEDORA-MODULAR-2018-2b0846cb86

View File

@ -1,5 +1,5 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (beamrolling)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -1,176 +0,0 @@
Perform robust unit tests with PyHamcrest
======
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/web_browser_desktop_devlopment_design_system_computer.jpg?itok=pfqRrJgh)
At the base of the [testing pyramid][1] are unit tests. Unit tests test one unit of code at a time—usually one function or method.
Often, a single unit test is designed to test one particular flow through a function, or a specific branch choice. This enables easy mapping of a unit test that fails and the bug that made it fail.
Ideally, unit tests use few or no external resources, isolating them and making them faster.
_Good_ tests increase developer productivity by catching bugs early and making testing faster. _Bad_ tests decrease developer productivity.
Unit test suites help maintain high-quality products by signaling problems early in the development process. An effective unit test catches bugs before the code has left the developer machine, or at least in a continuous integration environment on a dedicated branch. This marks the difference between good and bad unit tests:tests increase developer productivity by catching bugs early and making testing faster.tests decrease developer productivity.
Productivity usually decreases when testing _incidental features_. The test fails when the code changes, even if it is still correct. This happens because the output is different, but in a way that is not part of the function's contract.
A good unit test, therefore, is one that helps enforce the contract to which the function is committed.
If a unit test breaks, the contract is violated and should be either explicitly amended (by changing the documentation and tests), or fixed (by fixing the code and leaving the tests as is).
While limiting tests to enforce only the public contract is a complicated skill to learn, there are tools that can help.
One of these tools is [Hamcrest][2], a framework for writing assertions. Originally invented for Java-based unit tests, today the Hamcrest framework supports several languages, including [Python][3].
Hamcrest is designed to make test assertions easier to write and more precise.
```
def add(a, b):
    return a + b
from hamcrest import assert_that, equal_to
def test_add():
    assert_that(add(2, 2), equal_to(4))  
```
This is a simple assertion, for simple functionality. What if we wanted to assert something more complicated?
```
def test_set_removal():
    my_set = {1, 2, 3, 4}
    my_set.remove(3)
    assert_that(my_set, contains_inanyorder([1, 2, 4]))
    assert_that(my_set, is_not(has_item(3)))
```
Note that we can succinctly assert that the result has `1`, `2`, and `4` in any order since sets do not guarantee order.
We also easily negate assertions with `is_not`. This helps us write _precise assertions_ , which allow us to limit ourselves to enforcing public contracts of functions.
Sometimes, however, none of the built-in functionality is _precisely_ what we need. In those cases, Hamcrest allows us to write our own matchers.
Imagine the following function:
```
def scale_one(a, b):
    scale = random.randint(0, 5)
    pick = random.choice([a,b])
    return scale * pick
```
We can confidently assert that the result divides into at least one of the inputs evenly.
A matcher inherits from `hamcrest.core.base_matcher.BaseMatcher`, and overrides two methods:
```
class DivisibleBy(hamcrest.core.base_matcher.BaseMatcher):
    def __init__(self, factor):
        self.factor = factor
    def _matches(self, item):
        return (item % self.factor) == 0
    def describe_to(self, description):
        description.append_text('number divisible by')
        description.append_text(repr(self.factor))
```
Writing high-quality `describe_to` methods is important, since this is part of the message that will show up if the test fails.
```
def divisible_by(num):
    return DivisibleBy(num)
```
By convention, we wrap matchers in a function. Sometimes this gives us a chance to further process the inputs, but in this case, no further processing is needed.
```
def test_scale():
    result = scale_one(3, 7)
    assert_that(result,
                any_of(divisible_by(3),
                       divisible_by(7)))
```
Note that we combined our `divisible_by` matcher with the built-in `any_of` matcher to ensure that we test only what the contract commits to.
While editing this article, I heard a rumor that the name "Hamcrest" was chosen as an anagram for "matches". Hrm...
```
>>> assert_that("matches", contains_inanyorder(*"hamcrest")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 43, in assert_that
    _assert_match(actual=arg1, matcher=arg2, reason=arg3)
  File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 57, in _assert_match
    raise AssertionError(description)
AssertionError:
Expected: a sequence over ['h', 'a', 'm', 'c', 'r', 'e', 's', 't'] in any order
      but: no item matches: 'r' in ['m', 'a', 't', 'c', 'h', 'e', 's']
```
Researching more, I found the source of the rumor: It is an anagram for "matchers".
```
>>> assert_that("matchers", contains_inanyorder(*"hamcrest"))
>>>
```
If you are not yet writing unit tests for your Python code, now is a good time to start. If you are writing unit tests for your Python code, using Hamcrest will allow you to make your assertion _precise_ —neither more nor less than what you intend to test. This will lead to fewer false positives when modifying code and less time spent modifying tests for working code.
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/8/robust-unit-tests-hamcrest
作者:[Moshe Zadka][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/moshez
[1]:https://martinfowler.com/bliki/TestPyramid.html
[2]:http://hamcrest.org/
[3]:https://www.python.org/

View File

@ -0,0 +1,132 @@
Perform robust unit tests with PyHamcrest
使用 PyHamcrest 执行健壮的单元测试
======
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/web_browser_desktop_devlopment_design_system_computer.jpg?itok=pfqRrJgh)
在[测试金字塔][1]的底部是单元测试。单元测试每次只测试一个代码单元,通常是一个函数或方法。
通常,设计单个单元测试是为了测试通过函数或特定分支选择的特定流,这使得失败的单元测试和导致失败的 bug 之间的映射变得容易。
理想情况下,单元测试使用很少或不使用外部资源,从而隔离它们并使它们更快。
_好_ 测试通过尽早发现 bug 并加快测试速度来提高开发人员的工作效率。_坏_ 测试降低了开发人员的工作效率。
单元测试套件通过在开发过程的早期发现问题来帮助维护高质量的产品。有效的单元测试在代码离开开发人员机器之前捕获 bug或者至少在特定分支上的持续集成环境中捕获 bug。这标志着好的和坏的单元测试之间的区别好的测试通过尽早捕获 bug 并使测试更快来提高开发人员的生产力。坏的测试降低了开发人员的工作效率。
当测试 _附带的特性_ 时,生产率通常会降低。当代码更改时测试失败,即时它仍然是正确的。发生这种情况是因为输出不同,但在某种程度上它不是函数契约的一部分。
因此,一个好的单元测试可以帮助执行函数所提交的契约。
如果单元测试中断,那意味着契约被违反了,应该明确修改(通过更改文档和测试),或者被修复(通过修复代码并保持测试不变)。
虽然将测试限制为只执行公共契约是一项需要学习的复杂技能,但有一些工具可以提供帮助。
其中一个工具是 [Hamcrest][2],一个用于编写断言的框架。最初是为基于 Java 的单元测试而发明的,它现在支持多种语言,包括 [Python][3]。
Hamcrest 旨在使测试断言更容易编写和更精确。
```
def add(a, b):
    return a + b
from hamcrest import assert_that, equal_to
def test_add():
    assert_that(add(2, 2), equal_to(4))  
```
这是一个用于简单功能的断言。如果我们想要断言更复杂的怎么办?
```
def test_set_removal():
    my_set = {1, 2, 3, 4}
    my_set.remove(3)
    assert_that(my_set, contains_inanyorder([1, 2, 4]))
    assert_that(my_set, is_not(has_item(3)))
```
注意,我们可以简单地断言结果的顺序为 `1`, `2``4`,因为集合不保证顺序。
我们也可以很容易用 `is_not` 来否定断言。这有助于我们编写 _精确的断言_,使我们能够把自己限制在执行职能的公共契约方面。
然而,有时候,内置功能都不是我们 _真正_ 需要的。在这些情况下Hamcrest 允许我们编写自己的匹配器。
想象一下以下功能:
```
def scale_one(a, b):
    scale = random.randint(0, 5)
    pick = random.choice([a,b])
    return scale * pick
```
我们可以自信地断言结果均匀地划分为至少一个输入。to 校正:???什么意思)
匹配器继承自 `hamcrest.core.base_matcher.BaseMatcher`,重写两个方法:
```
class DivisibleBy(hamcrest.core.base_matcher.BaseMatcher):
    def __init__(self, factor):
        self.factor = factor
    def _matches(self, item):
        return (item % self.factor) == 0
    def describe_to(self, description):
        description.append_text('number divisible by')
        description.append_text(repr(self.factor))
```
编写高质量的 `describe_to` 方法很重要,因为这是测试失败时显示的消息的一部分。
```
def divisible_by(num):
    return DivisibleBy(num)
```
按照惯例,我们将匹配器包装在一个函数中。有时这给了我们进一步处理输入的机会,但在这种情况下,我们不需要进一步处理。
```
def test_scale():
    result = scale_one(3, 7)
    assert_that(result,
                any_of(divisible_by(3),
                divisible_by(7)))
```
请注意,我们将 `divisible_by` 匹配器与内置的 `any_of` 匹配器结合起来,以确保我们只测试函数提交的内容。
在编辑这篇文章时我听到一个传言“Hamcrest” 这个名字被认为是 “matches” 的字谜。人力资源管理...
```
>>> assert_that("matches", contains_inanyorder(*"hamcrest")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 43, in assert_that
    _assert_match(actual=arg1, matcher=arg2, reason=arg3)
  File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 57, in _assert_match
    raise AssertionError(description)
AssertionError:
Expected: a sequence over ['h', 'a', 'm', 'c', 'r', 'e', 's', 't'] in any order
      but: no item matches: 'r' in ['m', 'a', 't', 'c', 'h', 'e', 's']
```
经过进一步的研究,我找到了谣言的来源:它是 “matchers” 的字谜。
```
>>> assert_that("matchers", contains_inanyorder(*"hamcrest"))
>>>
```
如果你还没有为你的 Python 代码编写单元测试,那么现在是开始的好时机。如果你正在为你的 Python 代码编写单元测试,那么使用 Hamcrest 将允许你使你的断言更加 _精确_,既不会比你想要测试的多也不会少。这将在修改代码时减少误报,并减少修改工作代码的测试所花费的时间。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/8/robust-unit-tests-hamcrest
作者:[Moshe Zadka][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/moshez
[1]:https://martinfowler.com/bliki/TestPyramid.html
[2]:http://hamcrest.org/
[3]:https://www.python.org/