Skip to content

Commit

Permalink
Merge pull request #3 from rolger/typescript_port
Browse files Browse the repository at this point in the history
feature: first migration to typescript
  • Loading branch information
codecop authored Dec 7, 2023
2 parents 23f2e6f + b5d4f2c commit 113a1bf
Show file tree
Hide file tree
Showing 27 changed files with 8,806 additions and 0 deletions.
13 changes: 13 additions & 0 deletions TypeScript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules/
npm-debug.log
typings
.idea
.iml
src/*.js
test/*.js
*.js.map
tsconfig.tsbuildinfo

dist/
coverage/
.nyc_output/
46 changes: 46 additions & 0 deletions TypeScript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Dependency Breaking Katas

Exercises to practice breaking dependencies in legacy
code to create tests for it.

## Goal

We have some legacy code. We need to make changes.
To make changes we need to introduce tests first.
We might have to change some code to enable testing.
We need to introduce so-called Seams (see [Michael
Feathers' Working Effectively with Legacy
Code](https://www.goodreads.com/book/show/44919.Working_Effectively_with_Legacy_Code)).

Changing code without test is risky, so we want to

* Only change as little code as possible.
* Rely on automated Refactoring tools as much as possible.
* You must not change the public API of the class.

### Assignments for Techniques

* Parametrise Constructor
* Subclass And Override Method
* Extract And Override Call
* Replace Global Reference With Getter
* Extract And Override Factory Method

Planned

* Extract Interface
* Adapt Parameter

### Task

Each task presents you with a class and some collaborators.

* Bring this class under test. Make sure to cover all paths in the core logic.
* There is an existing test class with a first test case which might or might not work.
* You cannot change collaborators because they are used by other teams as well.

### License

[New BSD License](http://opensource.org/licenses/bsd-license.php), see `license.txt` in repository.

(This is a copied document - do not edit!)
9 changes: 9 additions & 0 deletions TypeScript/TypeScript.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
33 changes: 33 additions & 0 deletions TypeScript/app/a/Assignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Assignment A
============

Goal
----

We have some legacy code. We need to make changes.
To make changes we need to introduce tests first.
We might have to change some code to enable testing.
We need to introduce so-called Seams (see Michael
Feathers' Working Effectively with Legacy Code).
Changing code without test is risky, so we want to

* Only change as little code as possible.
* Rely on automated Refactoring tools as much as possible.
* You must not change the public API of the class.

Problem Category
----------------

The system under test depends on a collaborator with
non deterministic behaviour. The collaborator is
initialised in the constructor.

Task
----

The given code calculates the discount for a purchase in
our online shop. The main logic is in `Discount`.

* Bring `Discount` under test. Make sure to cover all paths in the core logic.
* There is an existing `DiscountTest` with a first test case which might or might not work.
* You cannot change `MarketingCampaign` because it is used by other teams as well.
24 changes: 24 additions & 0 deletions TypeScript/app/a/discount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {Money} from "./money";
import {MarketingCampaign} from "./marketing-campaign";

export class Discount {

marketingCampaign: MarketingCampaign;

constructor() {
this.marketingCampaign = new MarketingCampaign();
}

discountFor(netPrice: Money): Money {
if (this.marketingCampaign.isCrazySalesDay()) {
return netPrice.reduceBy(15);
}
if (netPrice.moreThan(Money.ONE_THOUSAND)) {
return netPrice.reduceBy(10);
}
if (netPrice.moreThan(Money.ONE_HUNDRED) && this.marketingCampaign.isActive()) {
return netPrice.reduceBy(5);
}
return netPrice;
}
}
13 changes: 13 additions & 0 deletions TypeScript/app/a/marketing-campaign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export class MarketingCampaign {

public isActive(): boolean {
let now: Date = new Date();
return now.getMilliseconds() % 2 == 0;
}

public isCrazySalesDay(): boolean {
let now: Date = new Date();
return now.getDay() === 5;
}

}
25 changes: 25 additions & 0 deletions TypeScript/app/a/money.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export class Money {

public static readonly ONE_THOUSAND: Money = new Money(1000);
public static readonly ONE_HUNDRED: Money = new Money(100);

value: number;

constructor(value: number | string) {
if (typeof value === 'string') {
this.value = Number.parseFloat(value);
} else {
this.value = value;
}
}

reduceBy(p: number): Money {
// value.multiply(new BigDecimal(100 - p)).divide(new BigDecimal(100))
return new Money((this.value * (100 - p) / 100).toFixed(2));
}

moreThan(other: Money): boolean {
return this.value > other.value;
}

}
32 changes: 32 additions & 0 deletions TypeScript/app/b/Assignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Assignment B
============

Goal
----

We have some legacy code. We need to make changes.
To make changes we need to introduce tests first.
We might have to change some code to enable testing.
We need to introduce so-called Seams (see Michael
Feathers' Working Effectively with Legacy Code).
Changing code without test is risky, so we want to

* Only change as little code as possible.
* Rely on automated Refactoring tools as much as possible.
* You must not change the public API of the class.

Problem Category
----------------

The system under test contains non deterministic behaviour,
which is located in a few methods. The system under test can
be sub-classed.

Task
----

The given `MarketingCampaign` controls the marketing actions which
run on our online shop. During campaigns we e.g. offer discounts.

* Bring `MarketingCampaign` under test. Make sure to cover all paths in the core logic.
* There is an existing `MarketingCampaignTest` with a first test case which might or might not work.
20 changes: 20 additions & 0 deletions TypeScript/app/b/marketing-campaign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export class MarketingCampaign {

public isActive(): boolean {
return this.milliseconds() % 2 == 0;
}

public isCrazySalesDay(): boolean {
return this.dayOfWeek() == 5;
}

private milliseconds(): number {
let now: Date = new Date();
return now.getMilliseconds();
}

private dayOfWeek(): number {
let date: Date = new Date();
return date.getDay();
}
}
33 changes: 33 additions & 0 deletions TypeScript/app/c/Assignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Assignment C
============

Goal
----

We have some legacy code. We need to make changes.
To make changes we need to introduce tests first.
We might have to change some code to enable testing.
We need to introduce so-called Seams (see Michael
Feathers' Working Effectively with Legacy Code).
Changing code without test is risky, so we want to

* Only change as little code as possible.
* Rely on automated Refactoring tools as much as possible.
* You must not change the public API of the class.

Problem Category
----------------

The system under test depends on a collaborator with
database access. The database is not available in our
test environment. The collaborator is a static call.

Task
----

The given code creates the receipt with the calculated tax
for a purchase in our online shop. The main logic is in `Checkout`.

* Bring `Checkout` under test. Make sure to cover all paths in the core logic.
* There is an existing `CheckoutTest` with a first test case which might or might not work.
* You cannot change `ReceiptRepository` because it is used by other teams as well.
15 changes: 15 additions & 0 deletions TypeScript/app/c/checkout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {Money} from "./money";
import {Receipt} from "./receipt";
import {ReceiptRepository} from "./receipt-repository";


export class Checkout {

createReceipt(netAmount: Money): Promise<Error | boolean> {
let tax = netAmount.percentage(20);
let total = netAmount.add(tax);
let receipt: Receipt = new Receipt(netAmount, tax, total);

return ReceiptRepository.store(receipt);
}
}
34 changes: 34 additions & 0 deletions TypeScript/app/c/money.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export class Money {

public static readonly ZERO: Money = new Money(0);
public static readonly ONE_THOUSAND: Money = new Money(1000);
public static readonly ONE_HUNDRED: Money = new Money(100);

value: number;

constructor(value: number | string) {
if (typeof value === 'string') {
this.value = Number.parseFloat(value);
} else {
this.value = value;
}
}

add(other: Money): Money {
return new Money(this.value + other.value);
}

percentage(p: number): Money {
return new Money((this.value * p / 100).toFixed(2));
}

moreThan(other: Money): boolean {
return this.value > other.value;
}

format(): string {
return this.value.toFixed(2);
}


}
40 changes: 40 additions & 0 deletions TypeScript/app/c/receipt-repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {Receipt} from "./receipt";
import {Connection, MysqlError} from "mysql";

let mysql = require('mysql');

const db: Connection = mysql.createConnection({
host: 'localhost:3306',
user: 'store',
password: '12345',
database: 'store'
});

export class ReceiptRepository {

static store(receipt: Receipt): Promise<Error | boolean> {
return new Promise((resolve, reject) => {
db.connect((err: MysqlError) => {
if (err) {
reject(err);
} else {

db.query(
"insert into RECEIPT (AMOUNT, TAX, TOTAL) values(?, ?, ?)",
[receipt.amount.value, receipt.tax.value, receipt.total.value],
(err, results) => {
if (err) {
reject(err);
}
if (!results[0]) {
reject(new Error('Data not inserted?'))
}
resolve(true);
});

db.end();
}
});
});
}
}
8 changes: 8 additions & 0 deletions TypeScript/app/c/receipt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {Money} from "./money";

export class Receipt {
constructor(public amount: Money, public tax: Money, public total:Money) {
this.amount = Money.ZERO;
this.tax = Money.ZERO;
}
}
35 changes: 35 additions & 0 deletions TypeScript/app/d/Assignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Assignment D
============

Goal
----

We have some legacy code. We need to make changes.
To make changes we need to introduce tests first.
We might have to change some code to enable testing.
We need to introduce so-called Seams (see Michael
Feathers' Working Effectively with Legacy Code).
Changing code without test is risky, so we want to

* Only change as little code as possible.
* Rely on automated Refactoring tools as much as possible.
* You must not change the public API of the class.

Problem Category
----------------

The system under test depends on a collaborator with
slow behaviour due to a HTTP call. It is not guaranteed
that the REST server is available. The collaborator is
a Singleton and called multiple times.

Task
----

The given code calculates the shipping cost for a purchase
depending on the destination in our online shop. The main
logic is in `ShippingCost`.

* Bring `ShippingCost` under test. Make sure to cover all paths in the core logic.
* There is an existing `ShippingCostTest` with a first test case which might or might not work.
* You cannot change `RestCountriesAPI` because it is used by other teams as well.
Loading

0 comments on commit 113a1bf

Please sign in to comment.