“This is the 14th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Chapter 20 of the Definitive Guide to Android Programming, in which you will learn about unit testing. Unit testing is the process of writing small programs to verify the behavior of individual units of the main application, that is, testing individual classes.

Create SoundPool

SoundPool.Builder can create a SoundPool instance. SetMaxStreams (Int) specifies how many audio streams will be played simultaneously at any one time

BeatBox. Kt:

. private const val MAX_SOUNDS = 5 class BeatBox(private val assets: AssetManager) { ... private val soundPool = SoundPool.Builder().setMaxStreams(MAX_SOUNDS).build() ... }Copy the code

If you try to play a sixth audio after playing five, SoundPool will stop playing the first audio. You can also specify other different audio stream attributes using setAudioAttributes.

Documentation for the SoundPool class can be found at:

Developer.android.com/reference/a…

2. Visit Assets

You need to use the AssetManager object to access and play the audio file.

val assetPath = sound.assetPath
val assetManger = context.assets
val soundData = assetManger.open(assetPath)
Copy the code

For some apis (such as SoundPool) you need FileDescriptor. You can call assetManager.openfd (String) instead.

Load the audio file

Using SoundPool to load audio files is quick to respond, although it also requires pre-loading audio.

First add the soundId attribute to the Sound class, which is nullable and can be set to null if it has no value.

class Sound(val assetPath: String, var soundId: Int? = null) {
    val name = assetPath.split("/").last().removeSuffix(WAV)
}
Copy the code

Add a load(Sound) function to the BeatBox to load the audio.

    private fun load(sound: Sound) {
        val afd: AssetFileDescriptor = assets.openFd(sound.assetPath)
        val soundId = soundPool.load(afd, 1)
        sound.soundId = soundId
    }
Copy the code

Note: Calling openFd(String) may throw IOException, so remember to add the exception code. See Demo for details.

4. Play audio

Add the play(Sound) function to the BeatBox.

    fun play(sound: Sound) {
        sound.soundId?.let {
            soundPool.play(it, 1.0f, 1.0f, 1, 0, 1.0f)
        }
    }
Copy the code

The meanings of the parameters are as follows: AUDIO ID, left volume, right volume, Priority (invalid), whether to loop (0 indicates no loop, -1 indicates infinite loop), and playback rate (1 indicates normal speed).

Test dependencies

Start by adding two test tools:

  • Mockito

Java framework for creating mock objects

Github address: github.com/mockito/moc…

  • Hamcrest

Rule Matcher library “JUnit already has Hamcrest”

Add a Mockito dependency to build.gradle:

AndroidTestImplementation 'org. Mockito: mockito - core: 4.1.0' androidTestImplementation 'org. Mockito: mockito - the inline: 4.1.0'Copy the code

TestImplementation indicates that the dependency is only included in the test compilation of the application. The functions for creating and configuring mock objects are in mockito-core. Mockito -inline is a special dependency that makes it easier for Mockito to be used with Kotlin.

Create a test class

Open SoundViewModel.kt, Command+Shift+T (or Ctrl+Shift+T)

Select JUnit4 for the test library and check setUp/ @before.

All the classes in the androidTest directory are integrated test classes. The advantage is that the running environment (system framework and API) of the application test is the same as the running environment on the device after the application is released. The downside is that it’s time-consuming to set up and run because it’s running on a full-featured version of Android.

In the Test directory are the unit test classes. Unit tests run on the JVM and can be isolated from the Android runtime environment, so they are much faster.

The test directory is selected here to store the test classes.

7. Configure the test class

Functions containing common code annotated with @before are run once Before all tests. By convention, all unit test classes have a setUp() function annotated with @before.

Create SoundViewModel and Sound objects:

class SoundViewModelTest {

    private lateinit var sound: Sound
    private lateinit var subject:SoundViewModel

    @Before
    fun setUp() {
        sound = Sound("assetPath")
        subject = SoundViewModel()
        subject.sound = sound
    }
}
Copy the code

The reason for naming the SoundViewModel object with subject here is a convention for writing test code to facilitate identification and migration.

A first over, learn not to move. Continue to be divided into two, ha ha ha ~~~~~~

other

BeatBox Project Demo address:

Github.com/visiongem/A…


🌈 follow me ac~ ❤️

Public account: Ni K Ni K