首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用两个参数来完成任务?

如何使用两个参数来完成任务?
EN

Stack Overflow用户
提问于 2019-10-25 12:12:29
回答 1查看 433关注 0票数 1

在Serenity的书中,我们有一个只有一个参数的任务示例:

代码语言:javascript
复制
// spec/screenplay/tasks/add_a_todo_item.ts
import { PerformsTasks, Task } from 'serenity-js/protractor';

export class AddATodoItem implements Task {

static called(itemName: string) {                       // static method to improve the readability
    return new AddATodoItem(itemName);
}

performAs(actor: PerformsTasks): PromiseLike<void> {    // required by the Task interface
    return actor.attemptsTo(                            // delegates the work to lower-level tasks
        // todo: interact with the UI
    );
}

constructor(private itemName: string) {                 // constructor assigning the name of the item
                                                        // to a private field
}

假设您可以添加一个TodoItem应该完成的日期。我们会收到一个日期参数,比如“截止日期”。我不知道该怎么做。

第一个想法:

构造者:

代码语言:javascript
复制
constructor(private itemName: string, private deadline: Date) {
}

performAs:只需添加交互以键入截止日期即可

我们会有第二种静态方法。并且可能会更改被调用的方法返回。

谢谢你的解释。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-18 00:26:26

有几种方法可以做到这一点,这取决于哪些参数是强制性的,哪些参数是可选的,以及您希望任务拥有多少参数。

无参数

如果您有一个没有参数的任务,那么定义它的更简单的方法是使用Task.where 工厂功能

代码语言:javascript
复制
import { Task } from '@serenity-js/core';

const Login = () => Task.where(`#actor logs in`,
    Click.on(SubmitButton),
);

这与使用下面的类样式定义几乎是一样的,但是使用的代码要少得多:

代码语言:javascript
复制
class Login extends Task {
    performAs(actor: PerformsTasks) {
        return actor.attemptsTo( 
            Click.on(SubmitButton),
        );
    }

    toString() {
        return `#actor logs in`;
    }
}

单参数

对于应该接收一个参数的任务,可以使用上述方法:

代码语言:javascript
复制
const LoginAs = (username: string) => Task.where(`#actor logs in as ${ username }`, 
    Enter.theValue(username).into(UsernameField),
    Click.on(SubmitButton),
);

或者,您还可以按以下方式实现:

代码语言:javascript
复制
const Login = {
  as: (username: string) => Task.where(`#actor logs in as ${ username }`, 
      Enter.theValue(username).into(UsernameField),
      Click.on(SubmitButton),
  ),
}

我发现第二个版本更优雅,更符合Click.onEnter.theValue等内置交互,因为您将在演员流中调用Login.as而不是LoginAs

N参数

如果有一个以上的参数,但所有参数都是必需的,并且您只是在追求一个优雅的DSL,那么您可以按照以下方式扩展上面的模式:

代码语言:javascript
复制
const Login = {
    as: (username: string) => ({
        identifiedBy: (password: string) => Task.where(`#actor logs in as ${ username }`, 
            Enter.theValue(username).into(...),
            Enter.theValue(password).into(...),
            Click.on(SubmitButton),
    }),
}

然后调用上面的任务:

代码语言:javascript
复制
actor.attemptsTo(
    Login.as(username).identifiedBy(password),
);

这种设计并不特别灵活,因为它不允许您更改参数的顺序(也就是说,您不能说是Login.identifiedBy(password).as(username))或使某些参数是可选的,但是它提供了一个好看的DSL,并且实现工作相对较少。

更灵活

如果您需要更多的灵活性,例如,在一些参数是可选的情况下,您可以选择类样式的定义和准建造者模式。(我说“准”是因为它不会改变对象,而是产生新的对象)。

例如,假设系统需要提供用户名,密码可能是可选的。

代码语言:javascript
复制
class Login extends Task { 
    static as(username: string) {
        return new Login(username);
    }

    identifiedBy(password: string {
        return new Login(this.username, password);
    }

    constructor(
        private readonly username: string,
        private readonly password: string = '',
    ) {
        super();
    }

    performAs(actor: PerformsTasks) {
        return actor.attemptsTo(
            Enter.theValue(username).into(...),
            Enter.theValue(password).into(...),
            Click.on(SubmitButton),
        );
    }

    toString() {
        return `#actor logs in as ${ this.username }`;
    }
}

当然,您还可以更进一步,将任务实例化的行为与任务本身分离开来,如果不同的任务有足够的不同,需要单独实现,则实例化任务是有用的:

代码语言:javascript
复制
export class Login { 
    static as(username: string) {
        return new LoginWithUsernameOnly(username);
    }
}

class LoginWithUsernameOnly extends Task {

    constructor(
        private readonly username: string,
    ) {
        super();
    }

    identifiedBy(password: string {
        return new LoginWithUsernameAndPassword(this.username, password);
    }


    performAs(actor: PerformsTasks) {
        return actor.attemptsTo(
            Enter.theValue(username).into(...),
            Click.on(SubmitButton),
        );
    }

    toString() {
        return `#actor logs in as ${ this.username }`;
    }
}

class LoginWithUsernameAndPassword extends Task {

    constructor(
        private readonly username: string,
        private readonly username: string,
    ) {
        super();
    }


    performAs(actor: PerformsTasks) {
        return actor.attemptsTo(
            Enter.theValue(this.username).into(...),
            Enter.theValue(this.password).into(...),
            Click.on(SubmitButton),
        );
    }

    toString() {
        return `#actor logs in as ${ this.username }`;
    }
}

上述两种实现都允许您将任务调用为Login.as(username)Login.as(username).identifiedBy(password),但是第一个实现对密码使用一个空字符串的默认值,而第二个实现甚至不触及密码字段。

我希望这能帮到你!

1月

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58558314

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档