Short Answer
Unit tests cannot guarantee that no one will change the source code. That is not what they are for. They should depend on input ( or no input in some cases), and outcome. This also has to be deterministic. Please note to unit test a non-deterministic piece of code, one must create mocks to make it appear as deterministic.
The unit test you are asking for, as I will explain below in this answer, is to guarantee no one will change the source code; which of course is not possible.
Long Answer
Imagine you wrote an application that takes an input and puts double quotes around it. For example, you give it Test
and it returns "Test"
. To unit test that, you may write a few tests like below:
TestNoSpace
Test With a Space
Test With "Quotes"
You run your tests, and the expected output matches. Ok great! That will work that way for as long as no one changes the source code. If they change the source code but change only the structure of the source code, the tests will pass. If they change it, refactor it, the output will still be the same and you don't really care if they refactor it (change the structure) for as long as the output is the same. The tests will fail though if someone changed it from adding quotes to adding single quotes. Pretty trivial points we can agree on.
Now let's go to your question about testing MVC Views. That same idea applies, that given a certain input, you expect a certain output. For example, you may have a view:
<label>First Name:</label><Label>@Model.FirstName</Label>
Is that the input or the output? It is neither. It is source code. Similar to code you wrote for adding quotes which may look like:
public string AddQuotes(string value)
{
return "\"" + value + "\"";
}
You would never write a unit test to make sure no one changes the above code, would you? You only would write a test to make sure that it behaves correctly: Given a string, it returns the string with quotes around it.
So now I ask you the same question: Why would you write a test to make sure no one changes the structure of the cshtml
code?
You may say I don't care if the structure of cshtml
code is changed, I just want to make sure the Model.FirstName
is put in the correct place. Well, again, how would someone do that? Because the only way I can think for someone doing that is to change the structure of cshtml
code, nonetheless, it is change to the source code.
At this point you may ask, "OK fine! But what if I wanted to test that given the current source code in cshtml
, I expect a certain output by the Razor engine?" And the answer to that is: Do you have a doubt that Razor has a bug and you want to ensure it does things correctly? In other words, you would be unit testing Razor; which is obviously not something you are after or something one would do--unless, of course, one is building the Razor engine. You may still say, "I don't care if the label is moved down and more elements are added, I just want to make sure the Model.FirstName
is mapped to the correct element". And to that I will say: What if the developer changed it from a label
to a span
or an input
, now what? You see where I am going with this.
If you pay close attention, the cshtml
is input for Razor engine. Testing to make sure cshtml
is not changed would be the same as if you wrote a test to make sure no one changes an input to the AddQuotes
method above: It just makes no sense.
So again, the question comes down to this:
- What is it that you want to test?
- What is the input?
- What is the expected outcome?
- Give an input, can we deterministically expect an outcome?
The answer to the above questions would be:
- I want to test that the
Model.FirstName
is always mapped to the correct label.
- I, yes I am talking about myself, honestly don't know. Is it the
Model
you pass to the view? If yes, you can unit test that at the controller to make sure the Model
being passed is correct. Is it the CSHTML file? But that is source code that is passed as input to Razor and we would not test Razor as I have already explained above.
- I, yes I am talking about myself, honestly don't know. Is it the
_Layout.cshtml
plus the cshtml
file in question plus the inline JavaScript and CSS? What is it?
- Well we cannot answer this unless we can answer 2 & 3 above.
Therefore, testing such stuff in the UI, not all stuff in the UI (some can be unit tested, see below), is not only frowned upon, but it just does not make sense; at least it is not a good idea. The cshtml
file is source code and it makes no sense to write unit tests to make sure no one changes the source code.
OK, so we should not test UI?
No, that is absolutely not what I am saying! I am saying we cannot test that a certain field is mapped to the correct element in cshtml
or any other UI because that depends on the structure of the source code.
You should test the behavior of UI using something like https://www.selenium.dev/ to ensure when things are clicked, it behaves properly or whatever other tests you deem fit.
"To unit-test the repository, I write an integration test"
Wait... what? That's not a unit test of the repository. You are automating the test for it, but code under test still includes the DAL and the database. To unit test the repository you have you isolate it like you have for your business rules.