Nigdy nie rób tego drugiemy programiście, proszę. Załóżmy, że musisz się połączyć z zewnętrznym serwisem w kodzie. Dlaczego nie zrobić tego używając klasy ze zwykłymi metodami? Skąd pokusa, aby takie połączenie nawiązywać w statycznych metodach?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AwsUtil {
// ...
public static Table getDynamoDbTable(String tableName) {
DynamoDB dynamoDB = new DynamoDB(getDynamoClient());
return dynamoDB.getTable(tableName);
}
public static AmazonDynamoDB getDynamoClient() {
AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard().build();
return amazonDynamoDB;
}
}
Prawda, że to czyste wcielenie zła? Spotkanie wywołania takiego czegoś w kodzie boli… głównie jeśli chcemy napisać testy. Oczywiście da się z tego wybrnąć korzystając z kilku technik refaktoryzacyjnych. Możemy wynieść to wywołanie i schować za jakimś interfejsem opakowując zewnętrzne zależności w nasze klasy, tak jak opisałem to w tym artykule. Ale z poniższy kod przegina wszystkie możliwe granice dobrego smaku.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
@RequiredArgsConstructor
@Conditional(SimpleBeanEnabled.class)
public class SimpleSerive {
//...
}
public class SimpleBeanEnabled implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Table table = AWSUtil.getDynamoDbTable("anytable");
//...
return result;
}
}
A, najważniejsza kwestia. Ten kod jest dostarczany jako JAR. Także nic nie można z nim zrobić, a trzeba go używać w kodzie z racji legacy. Więc powyższe sztuczki pewnie by pomogły, ale nie w sytuacji, gdy ten fragment kodu jest readonly. Więc jak tutaj napisać test integracyjny podnoszący kontekst Springa, ale bez łączenia się z AWS? Jedyne rozwiązanie jakie przyszło mi do głowy to klasę SimpleSerive
schować za interfejsem, dorobić dla niego fake i w teście integracyjnym wykluczyć wsadzanie SimpleSerive
do kontekstu, a w zamian niego załadować fake. Śmiga, ale trzeba założyć przysłowiowe “gacie przez głowę”.
Przez takie sytuacje na projekcie nie ma testów, a co dopiero mówić o tych na odpowiednim poziomie. Bo przecież “testu nie da się tutaj napisać” albo “jak powstanie to będzie bez sensu”. A to nie powinno się odwrócić zależności? Że przy pisaniu kodu produkcyjnego nie powinno się myśleć o jego testowalności? Odpowiedź jest raczej tylko jedna.