From bb2a8b582b43accedd38366c9bd317ffccff8e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Sun, 1 Sep 2019 18:51:18 +0200 Subject: [PATCH 1/3] More specific exception Generally, it's not recommended to throw Exception. See for example https://rules.sonarsource.com/java/RSPEC-112 In class StreamPlayer, new Exception is changed into new UnsupportedOperationException As a consequence, StreamPlayerEventLauncher.call() no longer throws a checked exception. UnsupportedOperationException is an unchecked exception. --- .../goxr3plus/streamplayer/stream/StreamPlayer.java | 10 +++++----- .../streamplayer/stream/StreamPlayerEventLauncher.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index a2b644f..0bd6935 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -742,7 +742,7 @@ else if (previousStatus == Status.PAUSED) { * @param seconds Seconds to Skip */ //todo not finished needs more validations - public long seekSeconds(int seconds) throws Exception { + public long seekSeconds(int seconds) throws StreamPlayerException { int durationInSeconds = this.getDurationInSeconds(); //Validate @@ -774,7 +774,7 @@ public long seekSeconds(int seconds) throws Exception { * * @param seconds Seconds to Skip */ - public long seekTo(int seconds) throws Exception { + public long seekTo(int seconds) throws StreamPlayerException { int durationInSeconds = this.getDurationInSeconds(); //Validate @@ -800,11 +800,11 @@ public long seekTo(int seconds) throws Exception { // seek(bytes); // } - private void validateSeconds(int seconds, int durationInSeconds) throws Exception { + private void validateSeconds(int seconds, int durationInSeconds) { if (seconds < 0) { - throw new Exception("Trying to skip negative seconds "); + throw new UnsupportedOperationException("Trying to skip negative seconds "); } else if (seconds >= durationInSeconds) { - throw new Exception("Trying to skip with seconds {" + seconds + "} > maximum {" + durationInSeconds + "}"); + throw new UnsupportedOperationException("Trying to skip with seconds {" + seconds + "} > maximum {" + durationInSeconds + "}"); } } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerEventLauncher.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerEventLauncher.java index 525c4bf..b6766c9 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerEventLauncher.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerEventLauncher.java @@ -73,7 +73,7 @@ public StreamPlayerEventLauncher(Object source, Status playerStatus, int encoded } @Override - public String call() throws Exception { + public String call() { // Notify all the listeners that the state has been updated if (listeners != null) { listeners.forEach(listener -> listener From eafe607fc93f72ac229404f33e6e43591d7520c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Sun, 1 Sep 2019 20:28:36 +0200 Subject: [PATCH 2/3] Mockito + demo Mockito is a mocking library used to create faked instances of classes. The class doesn't need to exist yet; we can create a mock from an interface or a parent class. Mockito can also create spies, which intercept existing methods and check if and how they are called. The demonstration unit test uses spies. Mockito has JUnit as a dependency. To avaoid JUnit version number conflict, we back the Junit version from 5.5.1 to 5.1.1, which is what this verison of Mockito wants. --- pom.xml | 13 ++++-- .../streamplayer/stream/StreamPlayerTest.java | 44 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java diff --git a/pom.xml b/pom.xml index c0f4f2a..fc849b0 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.github.goxr3plus @@ -13,7 +13,7 @@ 1.8 1.8 UTF-8 - 5.5.1 + 5.1.1 @@ -165,6 +165,13 @@ test + + + org.mockito + mockito-junit-jupiter + 3.0.0 + test + diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java new file mode 100644 index 0000000..815da0e --- /dev/null +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java @@ -0,0 +1,44 @@ +package com.goxr3plus.streamplayer.stream; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class StreamPlayerTest { + + @Test + @DisplayName("Demonstration of spying") + void demonstrationOfSpyng() throws StreamPlayerException { + + final File audioFile = new File("Logic - Ballin [Bass Boosted].mp3"); + + // Setup the spy + final StreamPlayer streamPlayer = new StreamPlayer(); + final StreamPlayer spy = spy(streamPlayer); + + // Execute & verify + + // Call open, via the spy + spy.open(audioFile); + + // verify that getEncodedStreamPosition is called exactly two times + verify(spy, times(2)).getEncodedStreamPosition(); + + // Call play, via the spy + spy.play(); + + // Verify that getEncodedStreamPosition is now called 3 times (the 2 previous times + one more time) + verify(spy, times(3)).getEncodedStreamPosition(); + + spy.stop(); + // Verify that there are in total 4 calls of getEncodedStreamPosition after the player is stopped. + verify(spy, times(4)).getEncodedStreamPosition(); + + // We can only spy on public methods. + // TODO: Look into initAudioInputStream, and check if we really need to call getEncodedStreamPosition() twice. + } +} \ No newline at end of file From b59f43956122ec58942fb59c10855214f8dff249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Sun, 1 Sep 2019 20:28:36 +0200 Subject: [PATCH 3/3] Mockito + demo Mockito is a mocking library used to create faked instances of classes. The class doesn't need to exist yet; we can create a mock from an interface or a parent class. Mockito can also create spies, which intercept existing methods and check if and how they are called. The demonstration unit test uses spies. Mockito has JUnit as a dependency. To avaoid JUnit version number conflict, we back the Junit version from 5.5.1 to 5.1.1, which is what this verison of Mockito wants. --- pom.xml | 13 ++++-- .../streamplayer/stream/StreamPlayerTest.java | 44 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java diff --git a/pom.xml b/pom.xml index c0f4f2a..fc849b0 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.github.goxr3plus @@ -13,7 +13,7 @@ 1.8 1.8 UTF-8 - 5.5.1 + 5.1.1 @@ -165,6 +165,13 @@ test + + + org.mockito + mockito-junit-jupiter + 3.0.0 + test + diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java new file mode 100644 index 0000000..815da0e --- /dev/null +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerTest.java @@ -0,0 +1,44 @@ +package com.goxr3plus.streamplayer.stream; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class StreamPlayerTest { + + @Test + @DisplayName("Demonstration of spying") + void demonstrationOfSpyng() throws StreamPlayerException { + + final File audioFile = new File("Logic - Ballin [Bass Boosted].mp3"); + + // Setup the spy + final StreamPlayer streamPlayer = new StreamPlayer(); + final StreamPlayer spy = spy(streamPlayer); + + // Execute & verify + + // Call open, via the spy + spy.open(audioFile); + + // verify that getEncodedStreamPosition is called exactly two times + verify(spy, times(2)).getEncodedStreamPosition(); + + // Call play, via the spy + spy.play(); + + // Verify that getEncodedStreamPosition is now called 3 times (the 2 previous times + one more time) + verify(spy, times(3)).getEncodedStreamPosition(); + + spy.stop(); + // Verify that there are in total 4 calls of getEncodedStreamPosition after the player is stopped. + verify(spy, times(4)).getEncodedStreamPosition(); + + // We can only spy on public methods. + // TODO: Look into initAudioInputStream, and check if we really need to call getEncodedStreamPosition() twice. + } +} \ No newline at end of file