[Study Note] Design and Testability 20100410
之前在4月1日的时候,开始看 Jeremy D.Miller 的一些关于 TDD 和 Unit Test 的文章,结果没看两篇,就先去补课了。到今天为止,看完了几篇 Patterns in Practice 系列的文章,然后回过头来,开始看 Design and Testablity。
似乎 TDD Design Starter Kit 这个系列文章的先后顺序有点乱,至少我看到了两个版本——TDD Design Starter Kit 和 Design and Testability,不过其实顺序没有什么关系。
[TDD Design Starter Kit: Responsibilities, Cohesion, and Coupling]
Separation of Concerns
In computer science, separation of concerns(SoC) is the process of separating a computer program into distinct features that overlap in functionality as little as possible. A concern is any piece of interest or focus in program. Typically concerns are synonymous with features or behaviors. Progress towards SoC is traditionally achieved through modularity of programming and encapsulation (or “transparency” of operation), with the help of information hiding. Layered designs in information systems are also often based on separation of concerns (e.g., presentation layer, business logic layer, data access layer, database layer.)
Cohesion – A measure of whether a class has a well defined, meaningful responsibility. High cohesion is desirable.
Couling – More or less, how entangled or dependent a class is with other class. A loosely coupled design implie that classes or subsystems can largely be modified independently of one another.
It’s also much easier to make mistakes in big methods than in smaller methods.
[TDD Design Starter Kit: Dependency Inversion Principle]
Dependency Inversion Principle (DIP)
Depend upon Abstractions. Do not depend upon concretions.
Rules of Thumb to Use DIP
- Anytime your code calls out of the CLR, and maybe just the current AppDomain itself.
- Singleton’s.
- Interface points between major subsystems.
- Extension points.
Injected Singleton
这个貌似是StructureMap 曾经在 SourceForge.NET 上的一篇文章,不过在迁移到新的主站上之后不知去向。当然,在互联网上所有的文字都不会凭空消失。
Singleton Design Pattern
Ensure a class only has one instance, and provide a global point of access to it.
Usage
- Caching or object pooling.
- Easy access to an object instance.
- Using a Singleton as a single point of object construction to control a plugin.
Unit Testing witha a Singleton
Singleton with StructureMap
Singletons are Evil
[TDD Design Starter Kit: State vs. Interaction Testing]
interaction-based testing is verifying the expected interaction between a class and its dependencies. Typically you would use either a mock or a stub object as a stand-in for the real dependency. The unit test will verify that the expected interaction via method calls took place.
看到这里,我就知道自己一直不太会使用 mock 的原因就是我只是使用 State Testing 模式,而没有按照 Interaction Testing 的方式来考虑问题。
[TDD Design Starter Kit: Static Methods and Singletons May Be Harmful]
you cannot mock (or stub) a static method, period
never do anything in a static method that calls out of the current AppDomain (HttpContext objects, database calls, MSMQ manipulation, etc.)
Mocking the guts of the repository may end up obfuscating the real intention of a unit test.
我打算对于 singleton 的问题新开一篇学习笔记;对于 static method 的问题,我也需要尽快弄清楚,因为我自己的代码里面有太多的 static。
[TDD Design Starter Kit: It’s All about Assigning Responsibilities]
Just Use Mock Objects, Right?
use mock objects to test the interaction of our code with teh external resources.
“Bottom Up” Construction
unit tests should be simple to setup, isolated, fine-grained, and reveal the intention of the code being tested.
Single Responsibility Principle(SRP)
There should never be more than one reason for a class to change
One class, one responsibility
cohesion
Responsibility Driven Design
The structure of an OO application is largely determined by how you assign reponsibilities to the classes in the application.
Responsibility Driven Design (RDD)
an obligation to perform a task or know information
- Know things
- Do things
- Make decisions
Object Role Stereotypes
Stereotypes are simplified views that help you understand an object or component’s purpose.
five object role stereotypes
- Controller – Controls application execution. Makes decisions and delegates to other classes.
- Service Provider – Provides a service to other classes.
- Interfacer – Communicates actions to other layers or systems.
- Information Holder – Hold facts. Domain classes.
- Structure – Maintains relationship between other classes.
isolate the ugly - take any thing that is inconvenient during unit testing like database access and isolate this functionality behind an abstracted wrapper interface.
suggest Interfacer classes for the SMTP, MSMQ, and external interaction, these classes will definitely be mocked in unit tests.
The Skeleton Code
Wrapping Up
Responsibility Driven Design is well suited as a supplement to Test Driven Development
.
[A Simple Example of the “Humble Dialog Box”]
- Create a class for the smart object, and an interface class for the view. Pass the view to the smart object.
- Develop commands against the smart object, test first. Write your tests against a mock view.
- Create your dialog class and implement the view interface on it. Gestures on the dialog should delegate to commands on the smart object. Call from the smart object to the dialog should resolve to simple setter methods