Category Archives: CS-443

Software Quality Assurance and Testing Blog Post #4 (Program Graphs and DD Path Graphs)

The latest topic in my Software Quality Assurance and Testing class has been learning how to read and write program graphs and DD path graphs. We also have been learning how to make DD path graph tables that correspond with the DD path graphs and the program graphs. Our most recent assignment was all about these topics. With the amount of work we have put into learning these, the assignment proved to not be too difficult for me. It is generally easy to know how to read the program graphs because pretty much every node corresponds with a single line of code in a program. Where it gets tricky is when the program has loops and if statements. Converting to a DD path graph from the program graph is also not too hard if you know what you are doing. A lot of nodes from the program graph can be clumped together into single nodes (like all the instance variables for example). Lastly, creating the DD path graph table takes in account both the program graph and the DD path graph, but again is not too difficult to read or fill out. The amount of time we have spend on these topics in class while doing in-class activities has helped me tremendously, because looking at the graphs without knowing what you are looking at can be daunting and confusing. As much as I enjoy being able to understand the graphs and make them if I want, it is even more enjoyable knowing that these topics can all be used in real life. It is always very reassuring when I try to research topics from class and they seem to be very prominently used in the real world with lots of examples and helpful sources to teach me about them. In this case, these topics all seem to be used a lot and also seem to be very helpful for those who have used them before to study how a program could be working (or how it could be failing).

From the blog CS@Worcester – Tim Drevitch CS Blog by timdrevitch and used with permission of the author. All other rights reserved by the author.

Erockwood Post #1

In my operating systems class, we are learning about all of the important roles the operating system has in a computer. There are many managers that the operating system itself manages to keep everything running as smoothly as possible. One thing I am most interested in when thinking about operating systems is concurrency and multithreading. Most tasks are done serially, which is to say one at a time. This worked well back in the day when most computers had only one or two cores. Nowadays, however, CPUs usually have 4+ cores, and if all tasks an operating system does are serial, then 3/4 of the CPUs resources are not being utilized. This is where concurrency / parallelism / multithreading comes into play. With them, we allow programs/tasks to run simultaneously, using more than one CPU core, to do more work in less time.

The only problem with this is trying to write the programs/tasks to take advantage of more cores. I know when I first tried to create and run a simple C program that would use more than one core, it was very confusing on trying to have everything be worked on by a separate thread. Eventually, after some trial and error, I got it working, and it slowly started to make sense on how to write this type of program. In doing some very simple calculations like I was trying to do in my example program, there is not much performance to be gained from multithreading the program, but in much bigger programs with bigger calculations to be done, there is definitely some time that can be saved by multithreading the process.

From the blog CS@Worcester – Erockwood Blog by erockwood and used with permission of the author. All other rights reserved by the author.

Learn How You Fail

Failing is unavoidable and it happens to everyone at some point. In reality, anyone who has never failed at anything has either stopped challenging themselves or learnt to ignore their own mistakes.

Your skills are progressing but you are still failing and have some remaining weaknesses. So instead of drowning in a sea of self-pity over previous failures, develop some self-awareness of your own patterns, habits, behaviors, and other factors that play a role in causing you to fail. When you are aware of yourself and the things that mess you up, you give yourself the option of either trying to solve the issues or cut your losses. You cannot succeed in all, and recognizing your shortcomings is critical because it allows you to actively recognize distractions and concentrate on your goals.

Accept that there will be certain stuff you aren’t very good at.

Once you learn to accept your failures you can set realistic limitations on your goals.

Often times I get irritated by the fact I keep failing, but if I accept it, my failures become learning opportunities. I can then seek out guidance and learn new skills from someone who knows more about code than I do. It is hard, honest work to admit your shortcomings and it will take a lot of failures, but I am confident that eventually, it will all be worth the frustration.

From the blog cs@worcester – Coding_Kitchen by jsimolaris and used with permission of the author. All other rights reserved by the author.

Software Testing: Jacoco

For this week’s blog post I chose to focus on a topic that I had to research for an honors project, this being Jacoco. In case you are not familiar with it, Jacoco is a software tool that is used to test code coverage, which in short just involves checking how much of a system’s code is being tested. This may sound redundant if you, like myself, have only really been using tests on small scale projects, but as a program’s complexity increases so does the complexity of the tests required. Additionally you will have to write more and more tests, making it difficult to determine exactly what has been covered. Before anything else however, I am going to break down exactly how code coverage is checked.


Having not known about Jacoco at all, I found this article on Baeldung that was extremely useful in understanding how it worked. As I stated the essential idea is to check code coverage, which consists of line and branch coverage. Line coverage essentially means Jacoco will check how many lines of code are being executed during tests to determine which are actually being tested. Branch coverages is similar to this, but focuses on checking the logical splits in the program, such as conditionals like if statements. The total amount of branches present is then compared to the amount that were covered to give the results. There is one more aspect of a program Jacoco checks for, being cyclomatic complexity. This is essentially a measure of the logical complexity of the program, or how many branches the program has. Now that we know what Jacoco is we can discuss why you might want to use it.

This testing tool certainly has some major benefits for anyone working on a large system. If you are working on writing tests for a system, it may begin as something straightforward, but as the system grows it will become increasingly hard to track exactly what components are being tested. This is where Jacoco comes in, allowing you to see exactly what lines, or just classes, are being tested so you can ensure there is sufficient test coverage. Additionally it can show you the degree of logical complexity present in the system, which could then be adjusted accordingly. One point to keep in mind that is mention in this article is that you should not get tunnel vision when trying to increase code coverage. High code coverage does not necessarily mean the tests being run are adequately testing the system. It is more important to focus on writing a few functional tests for each component rather than just having a plethora of tests that do not really do much of value. This article discusses Jacoco in more detail than I can so if this interests you I would recommend checking it out!

Source:

https://www.baeldung.com/jacoco

From the blog CS@Worcester – My Bizarre Coding Adventures by Michael Mendes and used with permission of the author. All other rights reserved by the author.

Code Review

Link: https://smartbear.com/learn/code-review/what-is-code-review/

According to the article linked above, to code review is to consciously and systematically convene with one’s fellow programmers to check each other’s code for mistakes. There are many different ways to code review such as through an email thread, pair programming, over the shoulder, or tool assistance. Through email, a programmer can easily send their colleague a file with the un-reviewed code allowing both of them to exchange regardless of schedule or location. Pair programming is when two software developers work on the same code side by side, allowing both to more fluidly exchange ideas. Developing over the shoulder is similar to peer programming except only one developer actively works on the code while the other acts as support. Tool assistance allows for even more flexibility than email chains since it allows for code review through software-based code review tools.

Code review is a very simple concept as it is simply peer reviewing in the context of software development. The importance of peer review is that another person can examine and point out someone’s mistakes unlike automated processes. Developers are still human and make human errors which are less likely to be picked up through artificial means. And solely relying on tests written by the original developer runs the risk of overlooking errors not picked up by tests or in the worst case, following the assessments of a flawed test. That’s why peer review, and by extension code review, is so important to speeding up and streamlining software development.

From the blog CS@Worcester – Rainiery's Blog by rainiery and used with permission of the author. All other rights reserved by the author.

The difference between Stubs and Mocks

A mock is an object that can set an expected value, which will verify that the desired action has occurred. The stub is the object that you pass to the code under test. You can set expectations on it to work in specific ways, but those expectations are never verified. The stub’s properties will automatically behave as standard properties, and you cannot set expectations on them.

If you want to verify the code’s behavior under test, a simulation with appropriate expectations is used and validated. If you’re going to pass only values that might need to work somehow but are not the focus of the test, you can use stubs.

Important note: Stubs will never cause a test to fail. 

I believe the most significant difference is that you have written the stub with predetermined behavior. Thus, you will have a class that implements the dependencies that you have disguised for testing purposes (most likely an abstract class or interface), and a class will handle the method only through the response that is set. They don’t do anything fancy, and you’ve already written stub code for them outside of testing.

Simulations are expectations that stubs must set during testing. The simulation is not set up in a predetermined way, so you have the code to perform the simulation in your tests. The mockery is determined at run time because the code that sets expectations must be run before they do anything.

The difference between stubs and stubs

Tests written with simulation usually follow a test pattern of initialize-> set expectations -> exercise -> verify. The pre-written stub will be followed by an initialize-> exercise-> verify.

Similarities between stubs and stubs

The purpose of both is to remove all dependencies from testing a class or function so that your tests are more focused and straightforward when trying to prove it.

The most crucial difference between Stubs and Mocks is their intention. Explain this in the WHY stub and WHY simulation below

Suppose I’m writing test code for the Mac Twitter client’s public timeline controller

Here is the sample code for the test:

twitter_api.stub(:public_timeline).and_return(public_timeline_array)

client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)

controller.refresh_public_timeline

Stub: The network connection to the Twitter API is very slow, which makes my tests slow. We knew it would return the timeline, so we made a stub that simulated the HTTP Twitter API so that our test could sprint, even if I were offline.


Mock: We haven’t written any UI methods yet, and I’m not sure what we need to register for UI objects. We wanted to write test code to see how my controller would work with UI objects.

In short, there is a difference between Mock and Stub objects, and RhinoMocks recognize that they allow us to write tests that better illustrate their purpose. The mock object is used to define the expectation that, in this case, I want to call the method A () with such an argument. Record and verify this expectation with ridicule. On the other hand, Stubs have a different purpose: they do not record or validate expectations but rather allow us to “replace” the behavior and state of “fake” objects to take advantage of test scenarios.

https://martinfowler.com/articles/mocksArentStubs.html

View at Medium.com

From the blog haorusong by and used with permission of the author. All other rights reserved by the author.

Stubs vs. Mocks

            Having started to learn about stubs with relation to testing in class, I went to do some further research on the functionality and usefulness of this testing strategy. I found a great deal of articles comparing stubs with mocks and evaluating their differences. I haven’t heard of mock testing before, so this was interesting to look into. Turns out, it’s pretty similar to some work we did in class. I found this great article detailing the differences which also gives a simple, understandable example.

            The main difference in stubs vs mocks is that stubs are looking to see a certain behavior, while mocks are also setting an expectation and then verifying that expectation. This is demonstrated with the use of a couple examples. Stub methods are created in the example by not doing anything but printing out “_____ is working fine.” This is to check that the correct method is being called and in the proper context. On the other hand, a mock uses a third party library (Mockito) which creates a mock Mathematics object in a test setup. Then, still in setup, the expectation is set: when(maths.sub(2,1).thenReturn(1); This is just saying 2 – 1 = 1. And finally, this expectation is verified in the test with Assert.assertEquals(1, s.subNumbers(2,1)); If this explanation seems choppy, sorry, I tried to condense 44 lines of code down to just this. Anyways, the idea is that a mock object is made, expectations are set, and then they’re verified. So both stubs and mocks are useful kind of white-box-ish testing styles, but mocks seem to have a higher level of testability. This doesn’t mean they’re necessarily better or more useful, but they have their purpose too.

From the blog CS@Worcester – Marcos Felipe's CS Blog by mfelipe98 and used with permission of the author. All other rights reserved by the author.

Transpiler

 Transpilers, or source-to-source compilers, are tools that read source code written in one programming language and generate equivalent code in another language with a similar level of abstraction. A good example of a translator is the TypeScript translator, which translates TypeScript code into JavaScript. The Babel compiler can also be used for ES6 JS code to ES5 JS code.

Compilers also translate code from one language to another, but the level of abstraction is very different between the two languages. For example, compile from .java to .class files.

ES6 and ES5

To understand the translator, you must first understand the difference between ES6 and ES5 JavaScript. ES6 (ECMAScript 6) is the specification for the next version of JavaScript. Some of its major enhancements include modules, class declarations, lexical block scopes, iterators and generators, a commitment to asynchronous programming, deconstructing patterns, and appropriate tail calls.

The features are great, but most browsers do not support the specification until now. As a result, any UI application specification written in ES6 will not work in most browsers. To run these applications, you must convert this ES6 source code to the supported JavaScript version ES5. ES5 is supported by almost all browsers and is by far the most stable version.

ES6 – Brings “types” to JavaScript. Make it closer to strongly typed languages such as Java and C#. So far, most browsers don’t support it. It must be converted to ES5 to execute in the browser.

ES5 – Over the years, we’ve been writing plain JavaScript.

Translation unit

A compiler is a program-like compiler that converts ES6 JavaScript code into ES5 JavaScript code to run in a browser. When the compiler sees an expression that uses the language functionality that needs to be translated, it generates a logically equivalent expression. The resulting expression can be very similar to or very different from the source expression.

What does a translator do?

ES6 code => ES5 code (even ES4, ES3)

Sources

https://scotch.io/tutorials/javascript-transpilers-what-they-are-why-we-need-them

https://devopedia.org/transpiler

From the blog haorusong by and used with permission of the author. All other rights reserved by the author.

7 Types of Software Testing

This week I wanted to learn more about the types of software testing that are out there. In class we already learned about methods like black and white box testing. I wanted to see if there were more methods that we may not have covered. 

This article describes 7 of the most common software testing methods. It is important to note that software testing and software development as a whole is always changing. As such there are many more than just seven software testing methods and there will definitely be new methods created in the future. These seven here are just some of the most common. 

They are:

  1. Black Box Testing
  2. White Box Testing
  3. Acceptance Testing
  4. Automated testing
  5. Regression Testing
  6. Functional Testing
  7. Exploratory Testing

Something I found interesting about this article is the relationship the author outlined between automated and regression testing. Automated testing is making your tests run automatically and regression testing is testing to verify the system still works as it did before some changes were made. Automated and regression testing go hand in hand because as software is incrementally changed you have to perform regression testing often. This is the real purpose behind automated testing – you can test repeatedly.

Another interesting method that was discussed is exploratory testing. The author refers to it as a “lazy” method of testing but also acknowledges its merits. Exploratory testing is essentially looking at a certain area of an application and exploring for any unexpected behavior. This testing method does not have any test cases. While this testing method does not really apply to the small applications that we work with in class, it may be useful in the capstone course. In that course we are creating a much larger web application with a front and backend so exploring may prove useful. 

https://usersnap.com/blog/software-testing-basics/

From the blog CS@Worcester – Half-Cooked Coding by alexmle1999 and used with permission of the author. All other rights reserved by the author.

JavaScript Testing

Because we are using JavaScript in the capstone course, I wanted to look as the tools used for testing in JavaScript, especially since I only have experience with testing in Java.

Because JavaScript is for web development, tests usually have to be run in a browser. This can be in a regular browser in an HTML page with JS scripts, or in a headless browser from the command line which is faster as there is nothing rendering onscreen. You can also run tests in Node.js. jsdom is commonly used with this to simulate a browser with pure JavaScript.

There are also many testing tools with different functions. Some tools have multiple functions and some have only one.

  1. Test launchers are used to launch your tests in the browser or Node.js with user config. (Karma, Jasmine, Jest, TestCafe, Cypress, webdriverio)
  2. Testing structure providers help you arrange your tests in a readable and scalable way. (Mocha, Jasmine, Jest, Cucumber, TestCafe, Cypress)
  3. Assertion functions are used to check if a test returns what you expect it to return and if its’t it throws a clear exception. (Chai, Jasmine, Jest, Unexpected, TestCafe, Cypress)
  4. Generate and display test progress and summary. (Mocha, Jasmine, Jest, Karma, TestCafe, Cypress)
  5. Mocks, spies, and stubs to simulate tests scenarios, isolate the tested part of the software from other parts, and attach to processes to see they work as expected. (Sinon, Jasmine, enzyme, Jest, testdouble)
  6. Generate and compare snapshots to make sure changes to data structures from previous test runs are intended by the user’s code changes. (Jest, Ava)
  7. Generate code coverage reports of how much of your code is covered by tests. (Istanbul, Jest, Blanket)
  8. Browser Controllers simulate user actions for Functional Tests. (Nightwatch, Nightmare, Phantom, Puppeteer, TestCafe, Cypress)
  9. Visual Regression Tools are used to compare your site to its previous versions visually by using image comparison techniques. (Applitools, Percy, Wraith, WebdriverCSS)

https://medium.com/welldone-software/an-overview-of-javascript-testing-7ce7298b9870

From the blog CS@Worcester – Half-Cooked Coding by alexmle1999 and used with permission of the author. All other rights reserved by the author.