One place for hosting & domains

      Testing

      Testing Angular with Jasmine and Karma (Part 1)


      Our goal

      In this tutorial we will be building and testing an employee directory for a fictional company. This directory will have a view to show all of our users along with another view to serve as a profile page for individual users. Within this part of the tutorial we’ll focus on building the service and its tests that will be used for these users.

      In following tutorials, we’ll populate the user profile page with an image of the user’s favorite Pokemon using the Pokeapi and learn how to test services that make HTTP requests.

      What you should know

      The primary focus for this tutorial is testing so my assumption is that you’re comfortable working with TypeScript and Angular applications. As a result of this I won’t be taking the time to explain what a service is and how it’s used. Instead, I’ll provide you with code as we work through our tests.

      Why Test?

      From personal experience, tests are the best way to prevent software defects. I’ve been on many teams in the past where a small piece of code is updated and the developer manually opens their browser or Postman to verify that it still works. This approach (manual QA) is begging for a disaster.

      Tests are the best way to prevent software defects.

      As features and codebases grow, manual QA becomes more expensive, time consuming, and error prone. If a feature or function is removed does every developer remember all of its potential side-effects? Are all developers manually testing in the same way? Probably not.

      The reason we test our code is to verify that it behaves as we expect it to. As a result of this process you’ll find you have better feature documentation for yourself and other developers as well as a design aid for your APIs.

      Why Karma?

      Karma is a direct product of the AngularJS team from struggling to test their own framework features with existing tools. As a result of this, they made Karma and have transitioned it to Angular as the default test runner for applications created with the Angular CLI.

      In addition to playing nicely with Angular, it also provides flexibility for you to tailor Karma to your workflow. This includes the option to test your code on various browsers and devices such as phones, tablets, and even a PS3 like the YouTube team.

      Karma also provides you options to replace Jasmine with other testing frameworks such as Mocha and QUnit or integrate with various continuous integration services like Jenkins, TravisCI, or CircleCI.

      Unless you add some additional configuration your typical interaction with Karma will be to run ng test in a terminal window.

      Why Jasmine?

      Jasmine is a behavior-driven development framework for testing JavaScript code that plays very well with Karma. Similar to Karma, it’s also the recommended testing framework within the Angular documentation as it’s setup for you with the Angular CLI. Jasmine is also dependency free and doesn’t require a DOM.

      As far as features go, I love that Jasmine has almost everything I need for testing built into it. The most notable example would be spies. A spy allows us to “spy” on a function and track attributes about it such as whether or not it was called, how many times it was called, and with which arguments it was called. With a framework like Mocha, spies are not built-in and would require pairing it with a separate library like Sinon.js.

      The good news is that the switching costs between testing frameworks is relatively low with differences in syntax as small as Jasmine’s toEqual() and Mocha’s to.equal().

      A Simple Test Example

      Imagine you had an alien servant named Adder who follows you everywhere you go. Other than being a cute alien companion Adder can really only do one thing, add two numbers together.

      To verify Adder’s ability to add two numbers we could generate a set of test cases to see if Adder provides us the correct answer.

      Within Jasmine, this would begin with what’s referred to as a “suite” which groups a related set of tests by calling the function describe.

      // A Jasmine suite
      describe('Adder', () => {
      
      });
      

      From here we could provide Adder with a set of test cases such as two positive numbers (2, 4), a positive number and a zero (3, 0), a positive number and a negative number (5, -2), and so on.

      Within Jasmine, these are referred to as “specs” which we create by calling the function it, passing it a string to describe the functionality that’s being tested.

      describe('Adder', () => {
        // A jasmine spec
        it('should be able to add two whole numbers', () => {
          expect(Adder.add(2, 2)).toEqual(4);
        });
      
        it('should be able to add a whole number and a negative number', () => {
          expect(Adder.add(2, -1)).toEqual(1);
        });
      
        it('should be able to add a whole number and a zero', () => {
          expect(Adder.add(2, 0)).toEqual(2);
        });
      });
      

      Within each spec we call expect and provide it what is referred to as an “actual”—the call site of our actual code. After the expectation, or expect, is the chained “matcher” function, such as toEqual, which the testing developer provides with the expected output of the code being tested.

      There are many other matchers available to us other than toEqual. You can see a full list within Jasmine’s documentation.

      Our tests aren’t concerned with how Adder arrives at the answer. We only care about the answer Adder provides us. For all we know, this may be Adder’s implementation of add.

      function add(first, second) {
        if (true) { // why?
          if (true) { // why??
            if (1 === 1) { // why?!?1
              return first + second;
            }
          }
        }
      }
      

      In other words, we only care that Adder behaves as expected—we have no concern for Adder’s implementation.

      This is what makes a practice like test-driven development (TDD) so powerful. You can first write a test for a function and its expected behavior and get it to pass. Then, once it’s passing, you can refactor your function to a different implementation and if the test is still passing, you know your function is still behaving as specified within your tests even with a different implementation. Adder’s add function would be a good example!

      Angular setup

      We’ll begin by creating our new application using the Angular CLI.

      ng new angular-testing --routing
      

      Since we’ll have multiple views in this application we use the --routing flag so the CLI automatically generates a routing module for us.

      From here we can verify everything is working correctly by moving into the new angular-testing directory and running the application.

      cd angular-testing
      ng serve -o
      

      You can also verify the application’s tests are currently in a passing state.

      ng test
      

      Adding a home page

      Before creating a service to populate our home page with users, we’ll start by creating the home page.

      ng g component home
      

      Now that our component has been created, we can update our routing module’s (app-routing.module.ts) root path to HomeComponent.

      import { NgModule } from '@angular/core';
      import { RouterModule, Routes } from '@angular/router';
      import { HomeComponent } from './home/home.component';
      
      const routes: Routes = [
        { path: '', component: HomeComponent }
      ];
      
      @NgModule({
        imports: [RouterModule.forRoot(routes)],
        exports: [RouterModule]
      })
      export class AppRoutingModule { }
      

      Run the application if it isn’t already and you should now see “home works!” below the default template in app.component.html which was created by the CLI.

      Removing AppComponent tests

      Since we no longer need the default contents of AppComponent, let’s update it by removing some unnecessary code.

      First, remove everything in app.component.html so that only the router-outlet directive remains.

      <router-outlet></router-outlet>
      

      Within app.component.ts, you can also remove the title property.

      import { Component } from '@angular/core';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.css']
      })
      export class AppComponent { }
      

      Finally, you can update the tests in app.component.spec.ts by removing the two tests for some of the contents that were previously in app.component.html.

      import { async, TestBed } from '@angular/core/testing';
      import { RouterTestingModule } from '@angular/router/testing';
      import { AppComponent } from './app.component';
      describe('AppComponent', () => {
        beforeEach(async(() => {
          TestBed.configureTestingModule({
            imports: [
              RouterTestingModule
            ],
            declarations: [
              AppComponent
            ],
          }).compileComponents();
        }));
        it('should create the app', async(() => {
          const fixture = TestBed.createComponent(AppComponent);
          const app = fixture.debugElement.componentInstance;
          expect(app).toBeTruthy();
        }));
      });
      

      Testing an Angular service

      Now that our home page is set up we can work on creating a service to populate this page with our directory of employees.

      ng g service services/users/users
      

      Here we’ve created our users service within a new services/users directory to keep our services away from the default app directory which can get messy quick.

      Now that our service is created, we can make a few small changes to the test file services/users/users.service.spec.ts.

      I personally find injecting dependencies within it() to be a bit repetitive and harder to read as it’s done in the default scaffolding for our test file as shown below:

      it('should be created', inject([TestService], (service: TestService) => {
        expect(service).toBeTruthy();
      }));
      

      With a few minor changes, we can move this into the beforeEach removing the duplication from each it.

      import { TestBed } from '@angular/core/testing';
      import { UsersService } from './users.service';
      
      describe('UsersService', () => {
        let usersService: UsersService; // Add this
      
        beforeEach(() => {
          TestBed.configureTestingModule({
            providers: [UsersService]
          });
      
          usersService = TestBed.get(UsersService); // Add this
        });
      
        it('should be created', () => { // Remove inject()
          expect(usersService).toBeTruthy();
        });
      });
      

      In the code above, TestBed.configureTestingModule({}) sets up the service we want to test with UsersService set in providers. We then inject the service into our test suite using TestBed.get() with the service we want to test as the argument. We set the return value to our local usersService variable which will allow us to interact with this service within our tests just as we would within a component.

      Now that our test setup is restructured, we can add a test for an all method which will return a collection of users.

      import { of } from 'rxjs'; // Add import
      
      describe('UsersService', () => {
        ...
      
        it('should be created', () => {
          expect(usersService).toBeTruthy();
        });
      
        // Add tests for all() method
        describe('all', () => {
          it('should return a collection of users', () => {
            const userResponse = [
              {
                id: '1',
                name: 'Jane',
                role: 'Designer',
                pokemon: 'Blastoise'
              },
              {
                id: '2',
                name: 'Bob',
                role: 'Developer',
                pokemon: 'Charizard'
              }
            ];
            let response;
            spyOn(usersService, 'all').and.returnValue(of(userResponse));
      
            usersService.all().subscribe(res => {
              response = res;
            });
      
            expect(response).toEqual(userResponse);
          });
        });
      });
      

      Here we add a test for the expectation that all will return a collection of users. We declare a userResponse variable set to a mocked response of our service method. Then we use the spyOn() method to spy on usersService.all and chain .returnValue() to return our mocked userResponse variable wrapping it with of() to return this value as an observable.

      With our spy set, we call our service method as we would within a component, subscribe to the observable, and set its return value to response.

      Finally, we add our expectation that response will be set to the return value of the service call, userResponse.

      Why mock?

      At this point many people ask, “Why are we mocking the response?” Why did we provide our test a return value userResponse that we created ourselves, to manually set what’s being returned from our service? Shouldn’t the service call return the real response from the service, whether it’s a hard-coded set of users or a response from an HTTP request?

      This is a perfectly reasonable question to ask and one that can be hard to wrap your head around when you first begin testing. I find this concept is easiest to illustrate with a real world example.

      Imagine you own a restaurant and it’s the night before opening day. You gather everyone you’ve hired for a “test run” of the restaurant. You invite a few friends to come in and pretend they’re customers who will sit down and order a meal.

      No dishes will actually be served in your test run. You’ve already worked with your cooks and are satisfied they can make the dishes correctly. In this test run you want to test the transition from the customer ordering their dish, to the waiter sending that to the kitchen, and then the waiters fulfilling the kitchen’s response to the customer. This response from the kitchen may be one of a few options.

      1. The meal is ready.
      2. The meal is delayed.
      3. The meal cannot be made. We ran out of ingredients for the dish.

      If the meal is ready, the waiter delivers the meal to the customer. However, in the event that a meal is late or cannot be made, the waiter will have to go back to the customer, apologize, and potentially ask for a second dish.

      In our test run, it wouldn’t make sense to actually create the meals when we want to test the front-end’s (waiter’s) ability to fulfill the requests received from the backend (kitchen). More importantly, if we wanted to test our waiters could actually apologize to customers in the cases where a meal is delayed or cannot be made we would literally be waiting until our cooks were too slow or we ran out of ingredients before our tests for those cases could be confirmed. For this reason, we would “mock” the backend (kitchen) and give the waiters whatever scenario it is that we want to test.

      Similarly in code, we don’t actually hit the API when we’re testing various scenarios. We mock the response we may expect to receive and verify that our application can handle that response accordingly. Just like our kitchen example, if we were testing our application’s ability to handle an API call that failed we would literally have to wait for our API to fail to verify it could handle that case—a scenario that hopefully won’t be happening that often!

      Adding users

      To get this test to pass, we need to implement the service method in users.service.ts.

      First, we’ll start by adding our imports and a collection of employees to the service.

      import { Injectable } from '@angular/core';
      import { Observable, of } from 'rxjs'; // Add imports
      
      @Injectable({
        providedIn: 'root'
      })
      export class UsersService {
        users: Array<object> = [  // Add employee object
          {
            id: '1',
            name: 'Jane',
            role: 'Designer',
            pokemon: 'Blastoise'
          },
          {
            id: '2',
            name: 'Bob',
            role: 'Developer',
            pokemon: 'Charizard'
          },
          {
            id: '3',
            name: 'Jim',
            role: 'Developer',
            pokemon: 'Venusaur'
          },
          {
            id: '4',
            name: 'Adam',
            role: 'Designer',
            pokemon: 'Yoshi'
          }
        ];
      
        constructor() { }
      }
      

      Then, just below our constructor, we can implement all.

      all(): Observable<Array<object>> {
        return of(this.users);
      }
      

      Run ng test again and you should now have passing tests including the new tests for our service method.

      Add users to the home page

      Now that our service method is ready to use, we can work towards populating our home page with these users.

      First, we’ll update index.html with Bulma to help us with some styling.

      <!doctype html>
      <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>AngularTesting</title>
        <base href="https://www.digitalocean.com/">
      
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/x-icon" href="favicon.ico">
        <!--Add these-->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css">
        <script defer src="https://use.fontawesome.com/releases/v5.1.0/js/all.js"></script>
      </head>
      <body>
        <app-root></app-root>
      </body>
      </html>
      

      Then within home/home.component.ts we can add a call to our new service.

      import { Component, OnInit } from '@angular/core';
      import { UsersService } from '../services/users/users.service';
      
      @Component({
        selector: 'app-home',
        templateUrl: './home.component.html',
        styleUrls: ['./home.component.css']
      })
      export class HomeComponent implements OnInit {
        users;
      
        constructor(private usersService: UsersService) { }
      
        ngOnInit() {
          this.usersService.all().subscribe(res => {
            this.users = res;
          });
        }
      
      }
      

      First we import our service and inject it into our component’s constructor. Then we add a call to the service method within ngOnInit and set the return value to our component’s users property.

      To display these users to the view, update the template in home/home.component.html.

      <section class="section is-small">
        <div class="container">
          <div class="columns">
            <div class="column" *ngFor="let user of users">
              <div class="box">
                <div class="content">
                  <p class="has-text-centered is-size-5">{% raw %}{{user.name}}{% endraw %}</p>
                  <ul>
                    <li><strong>Role:</strong> {% raw %}{{user.role}}{% endraw %}</li>
                    <li><strong>Pokemon:</strong> {% raw %}{{user.pokemon}}{% endraw %}</li>
                  </ul>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>
      

      Now when you run ng serve and view the home page, you should see the users displayed within Bulma boxes.

      Finding a single user

      Now that our users are being populated into our home page, we’ll add one more service method for finding a single user that will be used for the user profile pages.

      First we’ll add the tests for our new service method.

      describe('all', () => {
        ...
      });
      
      describe('findOne', () => {
        it('should return a single user', () => {
          const userResponse = {
            id: '2',
            name: 'Bob',
            role: 'Developer',
            pokemon: 'Charizard'
          };
          let response;
          spyOn(usersService, 'findOne').and.returnValue(of(userResponse));
      
          usersService.findOne('2').subscribe(res => {
            response = res;
          });
      
          expect(response).toEqual(userResponse);
        });
      });
      

      Here we add a test for the expectation that findOne will return a single user. We declare a userResponse variable set to a mocked response of our service method, a single object from the collection of users.

      We then create a spy for usersService.findOne and return our mocked userResponse variable. With our spy set, we call our service method and set its return value to response.

      Finally, we add our assertion that response will be set to the return value of the service call, userResponse.

      To get this test to pass, we can add the following implementation to users.service.ts.

      all(): Observable<Array<object>> {
        return of(this.users);
      }
      
      findOne(id: string): Observable<object> {
        const user = this.users.find((u: any) => {
          return u.id === id;
        });
        return of(user);
      }
      

      Now when you run ng test you should see all of the tests in a passing state.

      Conclusion

      At this point I hope testing, both its benefits and the reason for writing them, is starting to become a bit more clear. Personally, I pushed off testing for the longest time and my reasons were primarily because I didn’t understand the why behind them and resources for testing were limited.

      What we’ve created in this tutorial isn’t the most visually impressive application but it’s a step in the right direction.

      In the next tutorial, we’ll create the user profile page and a service to retrieve a Pokemon image using the Pokeapi. We’ll learn how to test service methods that make HTTP requests and how to test components.

      If you want the tests to display in a more readable format within your terminal, there’s an npm package for this.

      First, install the package.

      npm install karma-spec-reporter --save-dev
      

      Once that’s finished, open src/karma.conf.js, add the new package to plugins, and update the progress value within reporters to spec.

      module.exports = function (config) {
        config.set({
          basePath: '',
          frameworks: ['jasmine', '@angular-devkit/build-angular'],
          plugins: [
            require('karma-jasmine'),
            require('karma-chrome-launcher'),
            require('karma-jasmine-html-reporter'),
            require('karma-coverage-istanbul-reporter'),
            require('@angular-devkit/build-angular/plugins/karma'),
            require('karma-spec-reporter') // Add this
          ],
          client: {
            clearContext: false // leave Jasmine Spec Runner output visible in browser
          },
          coverageIstanbulReporter: {
            dir: require('path').join(__dirname, '../coverage'),
            reports: ['html', 'lcovonly'],
            fixWebpackSourcePaths: true
          },
          reporters: ['spec', 'kjhtml'], // Update progress to spec
          port: 9876,
          colors: true,
          logLevel: config.LOG_INFO,
          autoWatch: true,
          browsers: ['Chrome'],
          singleRun: false
        });
      };
      

      Now when you run ng test you should have a more visually appealing output for your test suite.



      Source link

      Painless and Efficient Ways to Do Usability Testing


      This Tech Talk will be streaming live on Tuesday, July 28, 2020, 11:30 a.m.–12:30 p.m. ET.
      RSVP for free on GoToWebinar here.

      About the Talk

      Usability testing helps product builders and designers make informed design decisions that increase the odds of creating helpful and delightful user experiences.

      Rafael Mojica, VP of User Experience at DigitalOcean, will guide you through his favorite ways to carry out usability testing, and share insights on how you can validate the decisions you make while building.

      What You’ll Learn

      • What, when, and with whom to validate your product/service design decisions
      • Tips on what to do before, during, and after a usability study
      • Best practices on successful usability testing

      This Talk is Designed For

      Product builders and designers.

      About the Presenter

      Rafael Mojica, VP of User Experience at DigitalOcean, is a multidisciplinary interaction designer. He’s passionate about expanding the benefits of design thinking and communications into all aspects of a business.

      How to Join

      This Tech Talk is free and open to everyone. Join the live event on Tuesday, July 28, 2020, 11:30 a.m.–12:30 p.m. ET by registering on GoToWebinar here. and Rafael will be answering questions at the end.

      If you can’t make the live event, the recording and transcript will be published here as soon as it’s available.



      Source link

      How To Add Unit Testing to Your Django Project


      The author selected the Open Internet/Free Speech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      It is nearly impossible to build websites that work perfectly the first time without errors. For that reason, you need to test your web application to find these errors and work on them proactively. In order to improve the efficiency of tests, it is common to break down testing into units that test specific functionalities of the web application. This practice is called unit testing. It makes it easier to detect errors because the tests focus on small parts (units) of your project independently from other parts.

      Testing a website can be a complex task to undertake because it is made up of several layers of logic like handling HTTP requests, form validation, and rendering templates. However Django provides a set of tools that makes testing your web application seamless. In Django, the preferred way to write tests is to use the Python unittest module, although it is possible to use other testing frameworks.

      In this tutorial, you will set up a test suite in your Django project and write unit tests for the models and views in your application. You will run these tests, analyze their results, and learn how to find the causes of failing tests.

      Prerequisites

      Before beginning this tutorial, you’ll need the following:

      Step 1 — Adding a Test Suite to Your Django Application

      A test suite in Django is a collection of all the test cases in all the apps in your project. To make it possible for the Django testing utility to discover the test cases you have, you write the test cases in scripts whose names begin with test. In this step, you’ll create the directory structure and files for your test suite, and create an empty test case in it.

      If you followed the Django Development tutorial series, you’ll have a Django app called blogsite.

      Let’s create a folder to hold all our testing scripts. First, activate the virtual environment:

      • cd ~/my_blog_app
      • . env/bin/activate

      Then navigate to the blogsite app directory, the folder that contains the models.py and views.py files, and then create a new folder called tests:

      • cd ~/my_blog_app/blog/blogsite
      • mkdir tests

      Next, you’ll turn this folder into a Python package, so add an __init__.py file:

      • cd ~/my_blog_app/blog/blogsite/tests
      • touch __init__.py

      You’ll now add a file for testing your models and another for testing your views:

      • touch test_models.py
      • touch test_views.py

      Finally, you will create an empty test case in test_models.py. You will need to import the Django TestCase class and make it a super class of your own test case class. Later on, you will add methods to this test case to test the logic in your models. Open the file test_models.py:

      Now add the following code to the file:

      ~/my_blog_app/blog/blogsite/tests/test_models.py

      from django.test import TestCase
      
      class ModelsTestCase(TestCase):
          pass
      

      You’ve now successfully added a test suite to the blogsite app. Next, you will fill out the details of the empty model test case you created here.

      Step 2 — Testing Your Python Code

      In this step, you will test the logic of the code written in the models.py file. In particular, you will be testing the save method of the Post model to ensure it creates the correct slug of a post’s title when called.

      Let’s begin by looking at the code you already have in your models.py file for the save method of the Post model:

      • cd ~/my_blog_app/blog/blogsite
      • nano models.py

      You’ll see the following:

      ~/my_blog_app/blog/blogsite/models.py

      class Post(models.Model):
          ...
          def save(self, *args, **kwargs):
              if not self.slug:
                  self.slug = slugify(self.title)
              super(Post, self).save(*args, **kwargs)
          ...
      

      We can see that it checks whether the post about to be saved has a slug value, and if not, calls slugify to create a slug value for it. This is the type of logic you might want to test to ensure that slugs are actually created when saving a post.

      Close the file.

      To test this, go back to test_models.py:

      Then update it to the following, adding in the highlighted portions:

      ~/my_blog_app/blog/blogsite/tests/test_models.py

      from django.test import TestCase
      from django.template.defaultfilters import slugify
      from blogsite.models import Post
      
      
      class ModelsTestCase(TestCase):
          def test_post_has_slug(self):
              """Posts are given slugs correctly when saving"""
              post = Post.objects.create(title="My first post")
      
              post.author = "John Doe"
              post.save()
              self.assertEqual(post.slug, slugify(post.title))
      

      This new method test_post_has_slug creates a new post with the title "My first post" and then gives the post an author and saves the post. After this, using the assertEqual method from the Python unittest module, it checks whether the slug for the post is correct. The assertEqual method checks whether the two arguments passed to it are equal as determined by the "==" operator and raises an error if they are not.

      Save and exit test_models.py.

      This is an example of what can be tested. The more logic you add to your project, the more there is to test. If you add more logic to the save method or create new methods for the Post model, you would want to add more tests here. You can add them to the test_post_has_slug method or create new test methods, but their names must begin with test.

      You have successfully created a test case for the Post model where you asserted that slugs are correctly created after saving. In the next step, you will write a test case to test views.

      Step 3 — Using Django’s Test Client

      In this step, you will write a test case that tests a view using the Django test client. The test client is a Python class that acts as a dummy web browser, allowing you to test your views and interact with your Django application the same way a user would. You can access the test client by referring to self.client in your test methods. For example, let us create a test case in test_views.py. First, open the test_views.py file:

      Then add the following:

      ~/my_blog_app/blog/blogsite/tests/test_views.py

      from django.test import TestCase
      
      
      class ViewsTestCase(TestCase):
          def test_index_loads_properly(self):
              """The index page loads properly"""
              response = self.client.get('your_server_ip:8000')
              self.assertEqual(response.status_code, 200)
      

      The ViewsTestCase contains a test_index_loads_properly method that uses the Django test client to visit the index page of the website (http://your_server_ip:8000, where your_server_ip is the IP address of the server you are using). Then the test method checks whether the response has a status code of 200, which means the page responded without any errors. As a result you can be sure that when the user visits, it will respond without errors too.

      Apart from the status code, you can read about other properties of the test client response you can test in the Django Documentation Testing Responses page.

      In this step, you created a test case for testing that the view rendering the index page works without errors. There are now two test cases in your test suite. In the next step you will run them to see their results.

      Step 4 — Running Your Tests

      Now that you have finished building a suite of tests for the project, it is time to execute these tests and see their results. To run the tests, navigate to the blog folder (containing the application’s manage.py file):

      Then run them with:

      You’ll see output similar to the following in your terminal:

      Output

      Creating test database for alias 'default'... System check identified no issues (0 silenced). .. ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK Destroying test database for alias 'default'...

      In this output, there are two dots .., each of which represents a passed test case. Now you’ll modify test_views.py to trigger a failing test. First open the file with:

      Then change the highlighted code to:

      ~/my_blog_app/blog/blogsite/tests/test_views.py

      from django.test import TestCase
      
      
      class ViewsTestCase(TestCase):
          def test_index_loads_properly(self):
              """The index page loads properly"""
              response = self.client.get('your_server_ip:8000')
              self.assertEqual(response.status_code, 404)
      

      Here you have changed the status code from 200 to 404. Now run the test again from your directory with manage.py:

      You’ll see the following output:

      Output

      Creating test database for alias 'default'... System check identified no issues (0 silenced). .F ====================================================================== FAIL: test_index_loads_properly (blogsite.tests.test_views.ViewsTestCase) The index page loads properly ---------------------------------------------------------------------- Traceback (most recent call last): File "~/my_blog_app/blog/blogsite/tests/test_views.py", line 8, in test_index_loads_properly self.assertEqual(response.status_code, 404) AssertionError: 200 != 404 ---------------------------------------------------------------------- Ran 2 tests in 0.007s FAILED (failures=1) Destroying test database for alias 'default'...

      You see that there is a descriptive failure message that tells you the script, test case, and method that failed. It also tells you the cause of the failure, the status code not being equal to 404 in this case, with the message AssertionError: 200 != 404. The AssertionError here is raised at the highlighted line of code in the test_views.py file:

      ~/my_blog_app/blog/blogsite/tests/test_views.py

      from django.test import TestCase
      
      
      class ViewsTestCase(TestCase):
          def test_index_loads_properly(self):
              """The index page loads properly"""
              response = self.client.get('your_server_ip:8000')
              self.assertEqual(response.status_code, 404)
      

      It tells you that the assertion is false, that is, the response status code (200) is not what was expected (404). Preceding the failure message, you can see that the two dots .. have now changed to .F, which tells you that the first test case passed while the second didn’t.

      Conclusion

      In this tutorial, you created a test suite in your Django project, added test cases to test model and view logic, learned how to run tests, and analyzed the test output. As a next step, you can create new test scripts for Python code not in models.py and views.py.

      Following are some articles that may prove helpful when building and testing websites with Django:

      You can also check out our Django topic page for further tutorials and projects.



      Source link