如何测试类之间交换字典的合约?

问题描述 投票:0回答:1

我们的组织使用许多由不同团队维护的类并交换字典集合。我们希望确保提供商团队在违反合同时会收到通知。使用契约可以吗?

一个示例提供商类:

import java.util.Dictionary;
import java.util.Hashtable;

public class MoneyTransfer {
    public Dictionary<String, Object> toIBAN(Dictionary<String, Object> input) 
    {
        
        double amount = (Double) input.get("amount");
        String iban = input.get("iban").toString();
        
        Double commission = doTransfer(iban, amount);
        
        Dictionary<String, Object> output = new Hashtable<String, Object>();
        output.put("commission", commission);
        
        return output;
        
    }

    private double doTransfer(String iban, double amount) {
        // TODO Auto-generated method stub
        return 0;
    }
}

因此,当开发人员进行此代码更改时,我们希望能够破坏合同测试,这将编译正常,但会破坏消费者:

String iban = input.get("account no").toString();
pact
1个回答
0
投票

我们通过在接受字典的实际类前面编写适配器 REST 服务来做到这一点:

@RequestMapping(
        value="/CALL_DICTIONARY_SERVICE", 
        method = { RequestMethod.POST })
public ResponseEntity<Object> callDictionaryService(@RequestBody Object request) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
    
    Dictionary<String, Object> input = DictionaryRequestFactory.createDictionary(request);
    
    Object dictionaryService = locateDictionaryService(request);
    
    Dictionary<String, Object> output = callDictionaryService(dictionaryService, input);
    
    Object response = RestResponseFactory.createResponse(output);

    return new ResponseEntity<Object>(response, HttpStatus.OK);
}
//Rest of the code omitted for simplicity..

消费者端使用 Pact 框架的简单扩展类构建合约:

@Pact(consumer="Money Transfer Consumer")
public RequestResponsePact pactTransferToIBAN(PactDslWithProvider dsl) {
    
    Dictionary<String, Object> input = new Hashtable<>();
    input.put("amount", "123");
    input.put("iban", "TR000123456");
    
    Dictionary<String, Object> output = new Hashtable<>();
    output.put("commission", "12");
    
    DictionaryDslWithProvider builder = new DictionaryDslWithProvider(dsl);
    
    return builder
            .given("Sender account has enough money")
            .uponReceiving("TRANSFER_TO_IBAN")
            .dictionary(input)
          .willRespondWith()
            .dictionary(output)
          .toPact();
}

扩展类将字典参数转换为 REST 服务参数:

public class DictionaryDslWithProvider {

    PactDslWithProvider baseDsl;
    
    public DictionaryDslWithProvider(PactDslWithProvider baseDsl) {
        this.baseDsl = baseDsl;
    }
    
    public DictionaryDslWithState given(String state) {
        PactDslWithState dsl = baseDsl.given(state);
        return new DictionaryDslWithState(dsl);
    }
}
public class DictionaryDslWithState {

    PactDslWithState baseDsl;
    
    public DictionaryDslWithState(PactDslWithState dsl) {
        baseDsl = dsl;
    }

    public DslRequestWithoutDictionary uponReceiving(String dictionaryServiceName) {
        return new DslRequestWithoutDictionary(baseDsl.uponReceiving(dictionaryServiceName)
                .path("/CALL_DICTIONARY_SERVICE"
                ,dictionaryServiceName
                );
    }
}
public class DslRequestWithoutDictionary {

    PactDslRequestWithPath req;
    private String dictionaryServiceName;
    
    public DslRequestWithoutDictionary(PactDslRequestWithPath pactDslRequestWithPath, String dictionaryServiceName) {
        req = pactDslRequestWithPath;
        this.dictionaryServiceName = dictionaryServiceName;
    }

    public PactDslRequestWithDictionary dictionary(Dictionary<String, Object> dictionary) {
        
        String jsonBody = dictionaryToJsonBody(dictionary, dictionaryServiceName);
        
        return new PactDslRequestWithDictionary(
                req
                    .method("POST")
                    .body(jsonBody)
                    );
    }
    //Rest of the code omitted for simplicity..
}
public class PactDslRequestWithDictionary {

    PactDslRequestWithPath body;
    
    public PactDslRequestWithDictionary(PactDslRequestWithPath body) {
        this.body = body;
    }

    public DictionaryDslResponse willRespondWith() {
        return new DictionaryDslResponse(body.willRespondWith());
    }
}

当消费者创建合约时,他会得到以下内容:

Method:POST
Path:/CALL_DICTIONARY_SERVICE
Body:
{
    "amount": "123",
    "iban": "TR000123456",
    "_DICTIONARY_SERVIS_NAME_": "TRANSFER_TO_IBAN"
}

Provider 使用合约中提到的字典服务名称来查找正确的方法,并使用从 JSON 转换为字典的输入来调用它。

© www.soinside.com 2019 - 2024. All rights reserved.