Testing Tips: Avoid sleep in tests

Hi πŸ‘‹,

In this article I wanna show a testing tip that I’ve recently learned myself by reading Software Engineering at Google: Lessons Learned from Programming Over Time. The technique improved the way I write unit tests.

When I’m writing bigger unit tests, I have execute something in the background, like for example publishing a message to a message broker, wait for the message to be published and then consume it to test that what I published is correct.

When waiting for the message to be published or any other operation that required waiting in tests I used to call a sleep function, for a second or two, this is decent for few tests but if your tests grow then this approach does not scale well. Imagine if you’re having 50 tests and each test sleeps for one second, it would take at least 50 seconds to run the test suite, which is a lot of wasted time.

The better approach is to use a timeout and polling, you can poll at every millisecond to see if your test has done what you wanted to do instead of sleeping, this will improve the tests and reduce the execution time by a lot!

Let’s demonstrate this will a small example using the Golang programming language, I’m not going to use any external dependencies to demonstrate this technique but you can apply it everywhere you’re calling something that blocks or if you need to wait for something.

What we’re going to test is a simple struct with a method that blocks and modifies a field.

import (
	"math/rand"
	"time"
)

type SystemUnderTest struct {
	Result string
}

func (s *SystemUnderTest) SetResult() {
	go func() {
		time.Sleep(time.Duration(rand.Intn(3000)) * time.Millisecond)
		s.Result = "the_result"
	}()
}

func (s *SystemUnderTest) GetData() string {
	time.Sleep(time.Duration(rand.Intn(3000)) * time.Millisecond)
	return "the_data"
}

This is the not ideal way of testing it:

// A not very ideal way to test SetResult
func Test_SystemUnderTest_SetResult_NotIdeal(t *testing.T) {
	sut := SystemUnderTest{}
	sut.SetResult()

	time.Sleep(4 * time.Second)

	if sut.Result != "the_result" {
		t.Fatalf("Result not equal, want %s got %s", "the_result", sut.Result)
	}
}

SetResults takes between 0 to 3 seconds to run, since we’re waiting for the result we’re sleeping for 4 seconds.

=== RUN   Test_SystemUnderTest_SetResult_NotIdeal
--- PASS: Test_SystemUnderTest_SetResult_NotIdeal (4.00s)
PASS

A better way is to write a simple loop and poll for the result:

// A better way of testing the code
func Test_SystemUnderTest_SetResult(t *testing.T) {
	sut := SystemUnderTest{}
	sut.SetResult()

	passedMilliseconds := 0
	for {
		if passedMilliseconds > 4000 {
			t.Fatalf("timeout reached")
		}
		passedMilliseconds += 1
		time.Sleep(1 * time.Millisecond)
		if sut.Result != "" {
			break
		}
	}
	if sut.Result != "the_result" {
		t.Fatalf("Result not equal, want %s got %s", "the_result", sut.Result)
	}
}

Writing a loop and polling for the result will make the test more complex but it will execute faster. In this case the benefits outweigh the downsides.

=== RUN   Test_SystemUnderTest_SetResult
--- PASS: Test_SystemUnderTest_SetResult (2.08s)
PASS

If the language permits we can also use channels, let’s change the following function that returns a result after a random amount of time and test it.

func Test_SystemUnderTest_GetData(t *testing.T) {
	sut := SystemUnderTest{}

	timeoutTicker := time.NewTicker(5 * time.Second)
	result := make(chan string)

	// Get result when ready
	go func() {
		result <- sut.GetData()
	}()

	select {
	case <-timeoutTicker.C:
		t.Fatal("timeout reached")
	case actual := <-result:
		if actual != "the_data" {
			t.Fatalf("Data not equal, want: %s, got %s", "the_data", actual)
		}
	}
}

We avoided writing a loop with the use of a ticker and select.

In another case you may need to test HTTP calls on the local machine or any other library. Look for timeout options.

Go’s HTTP library let’s you specify a custom timeout for every call you make:

	client := http.Client{
		Timeout: 50 * time.Millisecond,
	}
	response, err := client.Get("http://localhost:9999/metrics")
	...

In Conclusion

Avoid the use of sleep in tests, try polling for the result instead or check if the blocking functions have parameters or can be configured to stop the execution after a timeout period.

Thanks for reading and I hope you’ve enjoyed this article! 🍻

Macbook Pro 2015 Battery and SSD Change | Repair | Environment

Hi πŸ‘‹,

I’m a big supporter of repair and the right to repair movement, I once fixed an old iPhone 6s and gifted it to my mom to use it as her daily phone and now I’ve decided to fix my old Macbook Pro Mid 2015 laptop instead of throwing it away.

The laptop has 4 major problems.

  1. The battery is dead.
  2. The audio is dead.
  3. The SSD is *almost* dead.
  4. The charging cable ruined.

If I manage to fix it, I still can use it for entertainment, internet browsing, light coding sessions and even some light video editing. I’ve used it exclusively from 2015 to late 2019 without problems and I still believe it can be used in 2023.

My plan is as follows:

The battery

The battery can be easily replaced and the only tools you’re needing are:

  • P5 pentalobe screwdriver
  • T5 torx screwdriver
  • prying tool
  • isopropyl alcohol

Unlike the following iFixit guide which makes you dissemble the entire Macbook, you can actually just disconnect the battery, remove the track-pad cable and start prying with alcohol.

Here’s a YouTube video demonstrating this:

If you follow the “ifixit” guide, you need to set aside at least 2-3 hours of your time and risk breaking your macbook, big thumbs down for this guide ifixit, as you’re trying to scare away people from performing the operation.

Of course they say the following: The solvent used to dissolve the battery adhesive can damage your speakers […]

There’s a trade-of between risk of damaging the speakers — which shouldn’t happen if you apply the alcohol with care and a syringe vs the risk of breaking cables & components by disassembling the whole Macbook by yourself.

Never the less I’ve pried out the battery and this is the end-result:

The laptop turns on but the CPU is limited at 1Ghz from what I’ve read on the internet.

The battery will cost about 30$ or 100$ depending from where I buy it.

The audio

I killed the audio by passing 9V to the headphone jack and it fried some chip inside the laptop I think.

Since this requires some fine PCB repair or replacing the entire PCB I’m not going to repair the audio at least for now.

I can still use the Macbook with bluetooth devices and the audio works.

The SSD

Apple uses a proprietary SSD that is quite expensive because why not. Let’s disrespect the customer, the environment for money and say it’s for security or what not.

I can use a standard NVMe SSD which I have lying around by purchasing a 3$ adaptor, which is a much better option than the proprietary SSD which costs about 150$ for 250GB of storage.

Another WIN is that if the computer fails I can still reuse my NVMe SSD in another computer.

Standart SSD = Environment + 1

Apple SSD = Environment – 2 … but, but it’s for security and safety!!!! It’s not the $$$.

The adapter can be purchased from Aliexpress.

The most SAD thing is that M1 Macs have the SSD soldered, so no more repair and hacks allowed outside Apple. Most of the computers will be dead after 2-3 years of intensive use. Thanks Apple, it really shows that you’re doing this for the environment.

If you’re planning to own a M1 Mac think about that it will become inevitably slow and Apple will probably do nothing about it. It will die outside of warranty and you’ll have to live without a computer for a few days / weeks until it is repaired if Apple doesn’t refuse the repair.

**rant**

Not to mention that it will drive the repair cost up, making the repair option very unappealing. There’s a thing where an user can just unplug a ssd in plug in a new one in 30 minutes while keeping the device and there’s another thing where a user has to send the device to a repair shop and wait a few days, weeks for the laptop to be repaired.

If you live in a country where Apple has no official entity, things get even worse. For example for a simple battery swap on the iPhone you need to reset it to factory settings (backup you data, lose all data, lose time restoring it) and stay a few days without a phone, which is sort of hard to do in this time and age.

The charging cable

I don’t know what materials Apple has used in their cables but here’s how my old charging cable looks now:

Surprisingly it still works.

I don’t want to replace the charger with another proprietary charger that I’m gonna throw away in a few years. Instead I’m going to buy the cable for 5$ then use a generic charger with USB C support.

Verdict

The repair of the computer will cost me about 50$-250$ on average, without audio which not so bad at all and, I can expect a few more years of usage, maybe a lot more if I install Ubuntu Linux on it.

Since 2012 Apple has made computers harder and harder to repair and is constantly screwing over customers. The right to repair bill that was passed in NYC in 2022 was also modified and it’s practically useless for the consumer because it allows Apple/Samsung and other providers will do their best to screw you over. A simple battery which costs 30-100$ will cost 400$-100$. Why you may ask?

Because Apple/Samsung glue the battery to the case and will sell you the WHOLE CASE instead of just the battery. It’s for the environment tho, and YOUR safety and security, just 130$ extra πŸ˜‰

For comparison here’s a screenshot for Samsung S10 battery part cost:

And here’s a screenshot of Samsung S21 battery part cost:

130$ for the environment πŸ˜‰ !

Note: Ifixit sells a Samsung S21 battery for ~30$ but: “This is an aftermarket part. It is not a genuine Samsung part.”.

I started making this post to tell the repair story about my old Macbook and ended up by telling another story on how big companies are screwing customers, the environment and making things worse for everyone except their pockets.

I’m grateful that people like Luis Rossmann exist and cover these issues in depth. Check him out on YouTube!

Also check out the right to repair movement in the EU.

That’s pretty much it!

Thanks for reading and happy environment protecting! πŸŒ΄πŸŒ²πŸŒ³πŸ’Έ