我在过去几天一直在研究自动验收测试,了解BDD&JBehave,FitNesse&Slim,Selenium和WebDriver等.
我刚刚看到这个,他演示了如何使用FitNesse的编写和维护这样的测试视频由罗伯特C.马丁.接近尾声时,有人问这些测试是否会触及用户界面.Martin接着解释说,对UI的耦合验收测试成本很高,因为对UI的更改非常频繁.我还可以猜测,这些测试只能在UI开发之后编写,这将使测试人员按照定义落后于计划.
我不得不问:替代方案是什么?Martin似乎暗示测试应该是一个隐藏的层,它会操纵应用程序的业务层.我的理解是,这需要额外的工作,更不用说它会暴露一个新的API,需要在生产环境中保护一次.
可以通过应用程序服务访问业务层就足够了吗?
你有什么经验吗?
感谢分享!
我们的 CI 构建的 GitVersion 步骤现在需要 4-5 分钟,我们无法真正弄清楚原因。以下是一些基本日志:
2018-09-25T14:31:02.4222252Z ##[section]Starting: GitVersion
2018-09-25T14:31:02.4227925Z ==============================================================================
2018-09-25T14:31:02.4228168Z Task : GitVersion Task
2018-09-25T14:31:02.4228396Z Description : Easy Semantic Versioning (http://semver.org) for projects using Git
2018-09-25T14:31:02.4228654Z Version : 3.6.5
2018-09-25T14:31:02.4229010Z Author : GitVersion Contributors
2018-09-25T14:31:02.4229302Z Help : See the [documentation](http://gitversion.readthedocs.org/en/latest/) for help
2018-09-25T14:31:02.4229565Z ==============================================================================
2018-09-25T14:31:02.4366228Z Preparing task execution handler.
2018-09-25T14:31:02.6709097Z Executing the powershell script: d:\w\_tasks\GitVersion_e5983830-3f75-11e5-82ed-81492570a08e\3.6.5\GitVersion.ps1
2018-09-25T14:31:03.0124372Z Current Directory: D:\w\_tasks\GitVersion_e5983830-3f75-11e5-82ed-81492570a08e\3.6.5
2018-09-25T14:31:03.0124924Z
2018-09-25T14:31:03.0125184Z
2018-09-25T14:31:03.0130879Z Sources Directory: d:\w\1\s
2018-09-25T14:31:03.0131239Z
2018-09-25T14:31:03.0131454Z
2018-09-25T14:31:03.0230450Z Invoking GitVersion with d:\w\1\s /output buildserver /nofetch
2018-09-25T14:31:03.0231023Z
2018-09-25T14:31:03.0231265Z …Run Code Online (Sandbox Code Playgroud) 考虑用户在Web应用程序上创建新帐户的常见用例,以及应用程序向用户的地址发送确认电子邮件.从我所看到的,这通常以3种方式之一实现:
第一种方法简单明了,但存在发送电子邮件后回滚事务的风险,从而使电子邮件无效.第二种方法更复杂,但它保证只有在用户创建实际成功时才发送电子邮件.第三种方法很简单,但是使用不应该知道的业务逻辑来加重Web层.
是不是有一种更简单的方法,也许是AOP驱动的,可以保证只有在用户创建事务实际成功时才会发送电子邮件?我是否认为第一种方法可能会失败?
我们正在使用Java EE + Spring堆栈并且愿意集成其他API(AOP?Spring Integration?)来实现这一目标.
干杯!
请考虑以下代码:
//our root app component
import {ChangeDetectionStrategy, Component, ErrorHandler, Injector, NgModule, ViewContainerRef} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {ToastModule, ToastsManager} from "ng2-toastr/ng2-toastr";
@Component({
selector: 'my-app',
template: `
<div>
name={{(test$|async).name}}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class App {
test$: Observable<{name:string}> = null;
constructor(toastr: ToastsManager, viewContainerRef: ViewContainerRef) {
toastr.setRootViewContainerRef(viewContainerRef);
}
}
export class CustomErrorHandler extends ErrorHandler {
constructor(private injector: Injector) { super(); }
handleError(err: any): void {
super.handleError(err);
this.injector.get(ToastsManager).error(err.message);
}
}
@NgModule({
imports: [ BrowserModule, BrowserAnimationsModule, …Run Code Online (Sandbox Code Playgroud) 使用Angular 4.3和以下的Plunkr.
请考虑以下组件:
@Component({
selector: 'my-app',
template: `
<div>
<button type="button" (click)="toggle()">Toggle</button>
<div #anchor></div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class App {
@ViewChild('anchor', {read: ViewContainerRef}) anchor: ViewContainerRef;
dynamicRef: ComponentRef;
value = true;
constructor(private cfr: ComponentFactoryResolver, private cdr: ChangeDetectorRef) {}
ngAfterViewInit(): void {
let factory = this.cfr.resolveComponentFactory(Dynamic);
this.dynamicRef = this.anchor.createComponent(factory);
this.dynamicRef.instance.value = this.value;
this.dynamicRef.changeDetectorRef.detectChanges();
}
toggle(): void {
this.value = !this.value;
this.dynamicRef.instance.value = this.value;
this.dynamicRef.changeDetectorRef.detectChanges();
}
}
@Component({
template: `Value: {{value}}`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class Dynamic { …Run Code Online (Sandbox Code Playgroud)