Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assert that "nothing happened" when writing unit test

When writing unit test, Is there a simple way to ensure that nothing unexpected happened ?

Since the list of possible side effect is infinite, adding tons of Assert to ensure that nothing changed at every steps seems vain and it obfuscate the purpose of the test.

I might have missed some framework feature or good practice.
I'm using C#7, .net 4.6, MSTest V1.

edit: The simpler example would be to test the setter of a viewmodel, 2 things should happen: the value should change and PropertyChanged event should be raised. These 2 things are easy to check but now I need to make sure that other properties values didn't changed, no other event was raised, the system clipboard was not touched...

like image 650
Titan Avatar asked Feb 02 '18 17:02

Titan


3 Answers

You're missing the point of unit tests. They are "proofs". You cannot logically prove a negative assertion, so there's no point in even trying.

The assertions in each unit test should prove that the desired behavior was accomplished. That's all.

If we reduce the question to absurdity, every unit test would require that we assert that the function under test didn't start a thermonuclear war.

Unit tests are not the only kind of tests you'll need to perform. There are functional tests, integration tests, usability tests, etc. Each one has its own focus. For unit tests, the focus is proving the expected behavior of a single function. So if the function is supposed to accomplish 2 things, just assert that each of those 2 things happened, and move on.

like image 181
Mark Benningfield Avatar answered Nov 19 '22 15:11

Mark Benningfield


One of the options to ensure that nothing 'bad' or unexpected happens is to ensure good practices of using dependency injection and mocking:

[Test]
public void TestSomething()
{
    // Arrange
    var barMock = RhinoMocks.MockRepository.GenerateStrictMock<IBar>();
    var foo = new Foo(barMock);
    // Act
    foo.DoSomething();
    // Assert
    ...
}

In the example above if Foo accidentally touches Bar, that will result in an exception (the strict mock) and the test fails. Such approach might not be applicable in all test cases, but serves as a good addition to other potential practices.

like image 38
Serge Semenov Avatar answered Nov 19 '22 15:11

Serge Semenov


Some addition to your edit:

In Test Driven Development you are writing only code, which will pass the test and nothing more. Furthermore you want to choose the simplest possible solutoin to accomplish this goal.

That said you will start most likely with a failing unit-test. In your situation you will not get a failing unit test at the beginning.

If you push it to the limits, you will have to check that format C:\ is not called in your application when you want to check every outcome. You might want to have a look at design principles like the KISS-principle (Keep it simple, stupid).

like image 2
Link Avatar answered Nov 19 '22 16:11

Link