Is it Possible to Test View with Unit Test?

If you already familiar with how MVVM works, in Angularjs, Android or any platform, you can put simple logic (if and else) inside View for your own convenience, thanks for technology! In the other hand, it become a problem when those logic isn’t simple anymore with bunch of branch of logic, although you already write unit test for your controller or presenter, you might catch some bugs on your View which caused by flawed logic or corrupted model.

Let’s take an example, here I will use Angularjs approach for this medium, you want to give a class to your link depending on your model value, you could simply write like this because WE CAN! (Why Angular? WHY?)

<a ng-class="{'btn-facebook': 'Facebook', 'btn-twitter': 'Twitter', 'btn-instagram': 'Instagram'}[vm.socialChannel]">{{vm.socialChannel}}</a>

Those blocks of logic will be like this on your Code

if (vm.socialChannel === 'Facebook') {
return 'btn-facebook'
} else if (vm.socialChannel === 'Twitter') {
return 'btn-twitter'
} else if (vm.socialChannel === 'Instagram') {
return 'btn-instagram'
}

You even can wrap it to a function so you can test it inside your View Model with Unit Test.

Those piece of code is looks simple, you even will not care to test it and confident enough to deliver your code to your client. But what if you need to show an element when ONLY having various of value, such as a Edit Post button will only appear if vm.message.user.id is equal to vm.user.id and vm.message.status is not locked or vm.currentThread.status is not closed. You might be found something more than this

<button ng-show="vm.message.user.id === vm.user.id && (vm.message.status !== 'closed' || vm.currentThread.status !== 'closed'">Edit Post</button>

You may be confused when something broken on the View if something missing on your code because the logic which you put on your View has complex logic.

Why you need to move your logic code inside your View to View Model?

  1. Of course you can test it on your unit test, for all logic without exception and increasing your code coverage number for you guys who crazy about code coverage.
  2. You don’t need to worry if your View is broken because some part of your model are unexpectedly corrupted. You already covered all possible scenario and implement preventive action and defensive code.
  3. Your View looks clean and tidy now. Eat that, dirty angularjs!

How do we start?

First of all, take out the block of logic at any element on your View to your View Model

From here we have this element before

<!-- this is View -->
<button ng-show="vm.message.user.id === vm.user.id && (vm.message.status !== 'closed' || vm.currentThread.status !== 'closed'">Edit Post</button>

and after some clean up,

<!-- this is View -->
<button ng-show="vm.isAbleToEdit()">Edit Post</button>

and your View Model

// This is View Model
var vm = this
vm.isAbleToEdit = function() {
return vm.message.user.id === vm.user.id && (vm.message.status !== 'closed' || vm.currentThread.status !== 'closed')
}

so you can test it with your Unit Test

it('isAbleToEdit method should return true if values are correct', function(){
vm.message.user.id = 'id123'
vm.user.id = 'id123'
vm.message.status = 'open'
vm.currentThread.status = 'public'
expect(vm.isAbleToEdit()).toEqual(true)
})
// And more test scenario begin here . . .

Simple, isn’t it? With this approach, you can have cleaner View codes, ~100% of coverage, and your code makes more sense.

Back to the question, the answer is YES. If you use template engine, or anything to put logic in your View, and only LOGIC in that View is testable, not to mention all interaction is testable, unless you are doing it with UI Test or integration test.

If you want to test interaction or behavior, or anything more than Unit Test could do for your View, use UI test instead or Integration Test.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.