-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d4e2152
commit 057f507
Showing
11 changed files
with
242 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
## Day 21: Changing tides. | ||
|
||
Today, you are still fighting and while the main storm | ||
passed you are still not out of danger yet! | ||
|
||
You will need to reach the nearby island quickly to recover | ||
since your ship is badly broken. | ||
|
||
Today's exercise is about fixing tests and fixing code. | ||
|
||
A refactoring is needed but a first step needs to be made | ||
in the tests. | ||
|
||
> **Challenge of day 21: Refactor the tests and production code to Output-based tests.** | ||
Before refactoring the code, here are some explanations regarding the different kind of tests as explained by Vladimir | ||
Khorikov in his book [Unit Testing Principles, Practices and Patterns.](https://www.manning.com/books/unit-testing). | ||
|
||
### Different styles of tests | ||
|
||
#### State-Based | ||
|
||
```java | ||
class StateBasedTests { | ||
@Test | ||
void it_should_add_given_product_to_the_order() { | ||
val product = new Product("Free Guy"); | ||
val sut = new Order(); | ||
|
||
sut.add(product); | ||
|
||
// Verify the state | ||
assertThat(sut.getProducts()) | ||
.hasSize(1) | ||
.allMatch(item -> item.equals(product)); | ||
} | ||
|
||
@AllArgsConstructor | ||
class Product { | ||
private final String name; | ||
} | ||
|
||
class Order { | ||
private final List<Product> products = new ArrayList<>(); | ||
|
||
List<Product> getProducts() { | ||
return Collections.unmodifiableList(products); | ||
} | ||
|
||
void add(Product product) { | ||
products.add(product); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
![State-Based](img/state-based.png) | ||
|
||
#### Output-Based | ||
|
||
```java | ||
class OutputBasedTests { | ||
@Test | ||
void discount_of_2_products_should_be_2_percent() { | ||
val product1 = new Product("Kaamelott"); | ||
val product2 = new Product("Free Guy"); | ||
|
||
// Call on the SUT (here PriceEngine) | ||
// No side effects -> Pure function | ||
val discount = PriceEngine.calculateDiscount(product1, product2); | ||
|
||
assertThat(discount).isEqualTo(0.02); | ||
} | ||
} | ||
``` | ||
|
||
![Output-Based](img/output-based.png) | ||
|
||
#### Communication-Based | ||
|
||
```java | ||
class CommunicationBasedTests { | ||
@Test | ||
void greet_a_user_should_send_an_email_to_it() { | ||
final var email = "john.doe@email.com"; | ||
final var emailGatewayMock = mock(EmailGateway.class); | ||
// Substitute collaborators with Test Double | ||
final var sut = new Controller(emailGatewayMock); | ||
|
||
sut.greetUser(email); | ||
|
||
// Verify that the SUT calls those collaborators correctly | ||
verify(emailGatewayMock, times(1)).sendGreetingsEmail(email); | ||
} | ||
|
||
interface EmailGateway { | ||
Try<String> sendGreetingsEmail(String email); | ||
} | ||
|
||
@AllArgsConstructor | ||
class Controller { | ||
private final EmailGateway emailGateway; | ||
|
||
public Try<String> greetUser(String email) { | ||
return emailGateway.sendGreetingsEmail(email); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
![Communication-Based](img/communication-based.png) | ||
|
||
![snippet of the day](snippet.png) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns="http://maven.apache.org/POM/4.0.0" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>com.advent-of-craft</groupId> | ||
<artifactId>advent-of-craft2023</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>audit</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
<properties> | ||
<mockito-core.version>4.8.1</mockito-core.version> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.mockito</groupId> | ||
<artifactId>mockito-core</artifactId> | ||
<version>${mockito-core.version}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package audit; | ||
|
||
import java.nio.file.Paths; | ||
import java.time.LocalDateTime; | ||
import java.time.format.DateTimeFormatter; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class AuditManager { | ||
private final int maxEntriesPerFile; | ||
private final String directoryName; | ||
private final FileSystem fileSystem; | ||
|
||
public AuditManager(int maxEntriesPerFile, String directoryName, FileSystem fileSystem) { | ||
this.maxEntriesPerFile = maxEntriesPerFile; | ||
this.directoryName = directoryName; | ||
this.fileSystem = fileSystem; | ||
} | ||
|
||
public void addRecord(String visitorName, LocalDateTime timeOfVisit) { | ||
String[] filePaths = fileSystem.getFiles(directoryName); | ||
String[] sorted = sortByIndex(filePaths); | ||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | ||
String newRecord = visitorName + ";" + timeOfVisit.format(dateTimeFormatter); | ||
|
||
if (sorted.length == 0) { | ||
String newFile = Paths.get(directoryName, "audit_1.txt").toString(); | ||
fileSystem.writeAllText(newFile, newRecord); | ||
return; | ||
} | ||
|
||
int currentFileIndex = sorted.length - 1; | ||
String currentFilePath = sorted[currentFileIndex]; | ||
List<String> lines = fileSystem.readAllLines(currentFilePath); | ||
|
||
if (lines.size() < maxEntriesPerFile) { | ||
lines.add(newRecord); | ||
String newContent = String.join(System.lineSeparator(), lines); | ||
fileSystem.writeAllText(currentFilePath, newContent); | ||
} else { | ||
String newName = "audit_" + (currentFileIndex + 2) + ".txt"; | ||
String newFile = Paths.get(directoryName, newName).toString(); | ||
fileSystem.writeAllText(newFile, newRecord); | ||
} | ||
} | ||
|
||
private String[] sortByIndex(String[] filePaths) { | ||
return Arrays.stream(filePaths) | ||
.sorted() | ||
.toArray(String[]::new); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package audit; | ||
|
||
import java.util.List; | ||
|
||
public interface FileSystem { | ||
String[] getFiles(String directoryName); | ||
|
||
void writeAllText(String filePath, String content); | ||
|
||
List<String> readAllLines(String filePath); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package audit; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.mockito.Mockito; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
|
||
class AuditManagerTests { | ||
@Test | ||
void addsNewVisitorToANewFileWhenEndOfLastFileIsReached() { | ||
FileSystem fileSystemMock = Mockito.mock(FileSystem.class); | ||
when(fileSystemMock.getFiles("audits")) | ||
.thenReturn(new String[]{ | ||
"audits/audit_2.txt", | ||
"audits/audit_1.txt"} | ||
); | ||
when(fileSystemMock.readAllLines("audits/audit_2.txt")) | ||
.thenReturn(List.of( | ||
"Peter;2019-04-06 16:30:00", | ||
"Jane;2019-04-06 16:40:00", | ||
"Jack;2019-04-06 17:00:00" | ||
)); | ||
|
||
var sut = new AuditManager(3, "audits", fileSystemMock); | ||
|
||
sut.addRecord("Alice", LocalDateTime.parse("2019-04-06T18:00:00")); | ||
|
||
verify(fileSystemMock).writeAllText("audits/audit_3.txt", "Alice;2019-04-06 18:00:00"); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters