DEV Community

Discussion on: Everything That's Not Tested Will Break

Collapse
 
hilaberger92 profile image
Hila Berger

Hi Jan,
I really agree with what you're saying here.
In my experience, even the simplest method might break because of an annoying little bug that you didn't think about...
When you perform unit testing, do you use mocks or trying to avoid it?

Collapse
 
stealthmusic profile image
Jan Wedel

Hi Hila,

Yes, I’m definitely using mocks when needed. However, I’m using mocks only for very simple use cases, specifically defining return values . Sometimes it is tempting to do use a lot of verifications to check if your implementation actually does some calls. This is bad and very fragile because it reimplements the behavior of the class you test and will break as soon as you refactor something. It’s important to design methods in a functional way so you put something in and expect something out.
I even use mocking for integration tests. When I test Rest APIs, mostly I do the actual requests with some in-memory DB but probably mocking other internal services to throw exceptions for example.

Collapse
 
hilaberger92 profile image
Hila Berger

Hi Jan,
I didn't quite understand why using verifications to check if your implementation does some calls is a bad thing, can you elaborate on it?
Also, which mocking framework do you use?
Thanks a lot!

Thread Thread
 
stealthmusic profile image
Jan Wedel

I didn't quite understand why using verifications to check if your implementation does some calls is a bad thing, can you elaborate on it?

So first, it's not inherently bad. It depends on how and how often you use it.

Let me give you an example:

void methodA(int someInt, int someOtherInt) {
    objA.foo(someInt);
    objB.bar(someOtherInt);
}

When you write tests, that verifies calling both methods, especially in a specific order, you duplicate the implementation in your tests. Test should focus on checking results based on some input. That's what I means with "functional style". So I would always try not to have any such methods like the one above that only have side effects. Rather I would write methods like:

int methodA(int someInt) {
    int foo = objA.foo(someInt);
    int bar = objB.bar(someOtherInt);

    return foo + bar;
}

Now you can simply write a test for example

assertThat(instance.methodA(1 + 2)).isEqualTo(3);

When you figure out, that you can simplify your method by writing...

int methodA(int someInt, int someOtherInt) {
    return someInt + someOtherInt;
}

the test ist still green, because you tested the result, not the internal behaviour.

That's why TDD is so important. It forces you to design all of your classes, methods, functions in a way that they can easily be tested by simply putting some values in and expecting something out.

There are obviously exceptions to this "rule", but there should be a very good reason.

Side effects should only happen at the very boundary of the application, e.g. REST on one side and a DB on the other. All code in the middle can be written in a functional style without any side effects.

Also, which mocking framework do you use?

For Java: Mockito or Spring Test, see my other article for some examples on how to do integration tests: dev.to/stealthmusic/modern-java-de...

Thread Thread
 
hilaberger92 profile image
Hila Berger

Thanks a lot!
Have you heard about Typemock by any chance?

Thread Thread
 
stealthmusic profile image
Jan Wedel

Have you heard about Typemock by any chance?

Nope, not yet. I just looked it up, it's .NET and C/C++, right?

Thread Thread
 
hilaberger92 profile image
Hila Berger

Yes. My team and I are working with their product for .NET and we are satisfied. I wanted to hear from other people who use their product...I guess I'll just keep looking :)