Author Archives: rydercsblog

Why Testers Need to Know About Code Refactoring

https://www.softwaretestinghelp.com/code-refactoring/

Refactoring is the practice of improving code without changing the existing functionality. It is used to transform inefficient or complicated code into efficient and simpler code. Some reasons why a piece of code may need to be refactored are:

  • Code smells – indications that serious problems may exist in the code. Some common code smells are redundant code, declared variables that aren’t used anywhere, over-complicated design, and the existence of too many complicated loops or conditionals
  • Technical debt – when shortcuts are used that will require more work to fix later
  • Following agile – agile software development promotes incremental development. If code is changed without proper refactoring, it may create code smells or technical debt

Refactoring code seems like something that only developers need to care about. However, it is something that software testers need to know about as well. When code is refactored, the addition of new code or updating of old code may cause existing unit tests to fail. As a tester, refactoring of code means that in-depth testing and regression testing must be performed. In-depth testing includes all existing user flows to ensure that all functionalities are working the same as before. Regression testing is required to ensure that upgrading a module did not break the functionality of another piece of code. Refactoring code may also cause test automation scripts to fail. When refactored code is tested, scenarios such as business cases, user flows, user acceptance tests, and the existing functionality need to be validated.

I thought this blog post was interesting because I have never thought about refactoring from a tester’s perspective. Even when small changes are made, a tester must make sure that the changes don’t break any other parts of the code or alter the user experience. Since refactoring is only concerned with making existing code more efficient or easier to read, tests should not return different results after refactoring. I learned a few useful terms from this post such as technical debt, in-depth testing, and regression testing. Reading this blog has given me a new perspective on code refactoring and has enhanced my understanding of the topic.

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

Test Scenario vs Test Case

https://reqtest.com/testing-blog/test-scenario-test-case/

This blog post compares two important aspects of software testing: test scenarios and test cases. A test scenario is a high-level documentation of a use case. It is used to make sure that the end-to-end functioning of the software is working correctly. With this type of testing, clients, stakeholders, and developers help the testers create scenarios that ensure the software works as intended. Test scenarios look at software from the point of view of the user to determine real world scenarios and use cases. Some important reasons to use test scenarios are:

  • They help validate that software is working correctly for each use case
  • They help determine the real-world use of the software
  • They help find discrepancies and improve the user experience
  • They save time, money, and effort
  • They are vital in evaluating the end-to-end functionality of the software
  • They help build better test cases because the test cases are derived from the scenarios

A test case is a set of conditions that help determine whether the software being tested satisfies requirements and works correctly. It is a single executable test that contains step-by-step instructions to verify that software functions the way it’s supposed to. A test case is used to validate a test scenario. Normally, a test scenario contains multiple test cases which contain information on how to test the scenario. This information includes prerequisites, inputs, preconditions, expected results, and post-conditions. Test scenarios are extracted from user stories and test cases are extracted from scenarios.

Both test scenarios and test cases should be used to ensure a high test coverage. As agile practices become more common, test scenarios are being used more and more.

I thought that the content of this blog was interesting and useful. I learned the difference between test scenarios and test cases and why both of them are used. Since agile development environments are becoming so common it is very useful to understand what test scenarios are. It was interesting to learn how test scenarios and test cases are related because I had no idea what differentiated them before I read this post. Overall this was an informative article that I enjoyed reading.

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

Load Testing

https://reqtest.com/testing-blog/load-testing/

This blog post is an in-depth look at load testing. Load testing is a type of performance testing that identifies the limits to the operating capacity of a program. It is usually used to test how many users an application can support and whether the infrastructure that is being used can support it. Some examples of parameters that load testing can identify include response time, performance under different load conditions of system or database components, network delay, hardware limitations, and issues in software configuration.

Load testing is similar to stress testing, but the two are not the same. Load testing tests a system under peak traffic, while stress testing tests system behavior beyond peak conditions and the response of the system when it returns to normal load conditions. The advantages of load testing include improved scalability, reduction in system downtime, reduction in cost due to failures, and improved customer satisfaction. Some examples of load testing are:

  • Testing a printer by printing a large number of documents
  • Testing a mail server with many concurrent users
  • Testing a word processor by making a change in a large volume of data

The most popular load testing tools are LoadView, NeoLoad, WebLOAD, and Load Runner. However, load testing can also be done without any additional tools. The steps to do so are:

  • Create a dedicated test environment
  • Determine load test scenarios
  • Determine load testing transactions for the application
  • Execute the tests and monitor the results
  • Analyze the results
  • Refine the system and retest

This blog post did a good job at defining load testing and explaining why it is an important process. I had heard of stress testing previously, so I appreciated how the author described the differences between the two. The part that I thought was most useful was the section on the advantages of load testing. It makes it easy to see why load testing is important if you are building something like a web app. It was also useful to read about some of the most popular tools because I now have a reference if I ever need to do this kind of testing in the future. I’m glad I read this blog as load testing seems like a very important practice in the field of software testing.

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

Test Automation

https://abstracta.us/blog/software-testing/test-automation-patterns-and-good-practices/

This blog post discusses good practices to use with test automation. Automating tests can save time and decrease the amount of work that has to be done. Following these practices will help ensure that you get the most value out of automation.

Test Code Review

  • All levels of testing should be reviewed to examine their quality. This will help the tester discover bad practices or mismatches in the tests.

Apply Assertions

  • Assertions should be used to identify problems.
  • An assertion that’s too generic can create false negatives and false positives, so pay special attention in the definition of assertions.

Behavior-Driven Development (BDD)

  • A common language should be created for the business and engineers to be used as a starting point for development and testing.
  • User stories are defined and used as input for test cases.
  • BDD gives developers clear specifications and brings testability to a system.

Page Object Pattern for UI Testing

  • The use of design patterns increases scalability and maintainability
  • The page object pattern allows you to reuse knowledge of the structure of an application while having a minimal impact on tests.
  • This pattern strengthens tests by decoupling the structure of the user interface from the test code

Data-Driven Testing

  • With data-driven testing, automated tests are parameterized so that the same steps can be carried out with diverse amounts of test data
  • Adding data to the file creates new test cases

Parallel Execution of Tests

  • Using parallel execution options like Selenium will reduce testing time by running several tests at the same time.

I thought this blog was very interesting. While I have learned a little about test automation I haven’t used it enough to learn the best practices for it. It is important to learn these practices because the whole point of automation is to save time, and if you don’t do it correctly you will end up spending more time trying to fix your errors.

I thought the most interesting part of this post was the section on the page object pattern. This is a design pattern that I’ve never heard of. It seems to be very useful because it helps prevent you from breaking your tests when you change your code. This is a topic that I would like to learn more about and will keep in mind when I work with automated testing. Overall I thought this was a useful and well-written blog post.

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

Positive Testing

https://www.softwaretestinghelp.com/positive-testing/#more-37401

This article explains the technique of positive testing. Positive testing is one method of testing software to make sure that it is working correctly. With this technique a valid set of test data is used to check if an application is functioning as per the specification document. For example, if you are testing a textbox that can only accept numbers, a positive test would be entering numbers into the box. This is in contrast to negative testing, which would be entering something besides numbers to see if the application breaks. The goal of this is to see if an application works as desired when it is being used correctly. For this reason, positive testing should be the first step of test execution.

There are two techniques discussed that are used in positive testing. With boundary value analysis, a tester needs to create test data which falls within a data range. With equivalence partitioning, the test input is divided into equal partitions and values from each partition are used as test data.

I thought this article was very interesting because positive testing is something that I have always done as the first step in testing without realizing there is a name for it. I think it is natural to see if your application works correctly before you test for bugs by trying to break it. The part that I found most useful was the section on equivalence partitioning. I usually just try random inputs when I am testing something, but it makes a lot more sense to divide the possible inputs into equal partitions so that data from each partition can be tested.

This article will not significantly change how I work because I have always used positive testing as the first step. Although now I will make sure to use equivalence partitioning when I am testing. I am glad I read this article because now I have a good understanding of what positive testing is and I will not be confused if I run into the term in the future. Reading this article has changed the way I think about testing because now I understand that there are different testing types and techniques that should be followed correctly to make sure that a piece of software is stable and bug-free.

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

Introductory Post

This is my introductory post for CS-443-02.

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

Programming Flaw: Constructor That Does Real Work

http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/

This blog post talks about why having a constructor do too much work is a bad programming practice. When a constructor instantiates and initializes its collaborators, the result is often inflexible and can shut off the ability to inject test collaborators. The author gives a few reasons why this is a flaw:

  • It violates the Single Responsibility Principle – Mixing collaborator construction with initialization suggests that there is only one way to configure the class. Having object graph creation take place in the constructor violates the Single Responsibility Principle
  • Testing directly is difficult – If a constructor does a lot of work, you will have to do that work when creating the objects while testing
  • Subclassing and overriding to test are still flawed – When you use subclassing you will fail to test the method that you override
  • It forces collaborators on you – You don’t always want to create all an object’s collaborators when you test it

Signs that a constructor is doing too much work:

  • new keyword in the constructor
  • Static method calls in a constructor
  • Object not fully initialized after the constructor finishes
  • Conditional or looping logic in a constructor
  • Complex object graph creation in a constructor rather than using a factory or builder
  • Using a initialization block

Fixing the Flaw:

To fix this flaw you should remember to pass collaborators into your constructor rather than create them there. The responsibility for object graph creation and initialization should be moved into another object such as a builder, factory, or provider. These collaborators can then be passed into the constructor.

Overall, the phrase “work in the constructor” means doing anything that makes instantiating your object difficult or introducing test-double objects difficult.

I thought that this blog did a very thorough job of explaining why doing work in a constructor is a flaw that should be avoided. It did a good job explaining why it is a flaw, recognizing when it is happening, and explaining various methods to fix it. There are also a lot of code examples that demonstrate the problem more concretely and show how it can be fixed. After reading this blog I now have a better understanding of what should and should not be included in a constructor. This blog also introduced me to some new object-oriented programming concepts that are too specific to be covered in the classroom. Overall I thought this blog was very informative and I expect to use what I have learned in future programming projects.

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

Writing Clean, High Quality Code

https://www.butterfly.com.au/blog/website-development/clean-high-quality-code-a-guide-on-how-to-become-a-better-programmer

This blog discusses various techniques that can be used to make your code cleaner and easier to understand. Writing high quality code is very important for software that is updated over time, and the following tips will help improve your code readability and quality.

Variable and Method Names

  • Use names that reveal the intention of the variable or method
  • Use names that can be pronounced
  • With programming languages that support namespaces it is better to use them rather than prefixing names
  • Use one word per concept throughout the program. For example, don’t use get and fetch to do the same thing in different classes
  • Use solution domain names
  • Use verbs for method names and nouns for classes and attributes

Better Functions

  • The smaller the better
  • A function should only do one thing (single responsibility principle)
  • Less arguments are better
  • Functions should only do what the name suggests and nothing else
  • Avoid output arguments. If returning something is not enough then your function is probably doing more than one thing.
  • Throwing exceptions is better than returning different codes dependent on errors
  • Don’t repeat yourself

Comments

  • Don’t comment bad code, rewrite it
  • Explain your intention in comments
  • Warn of consequences in comments
  • Emphasize important points in comments
  • Always use doc comments
  • Any comments other than the above should be avoided
  • Never leave code commented. With source control software you can always revert back to old code. Comments can be used when debugging or programming, but commented code should never be checked in

Code Smells and Anti-Patterns

The following should be avoided:

  • Dead code
  • Speculative generality
  • Large classes
  • God object
  • Multiple languages in one file
  • Framework core modifications
  • Overuse of static
  • Magic numbers (should be replaced with const or var)
  • Long if conditions (replace with function)
  • Call super’s overwritten methods
  • Circular dependency and references
  • Sequential coupling
  • Hard-coding
  • Too much inheritance (composition is better)

I selected this blog because being able to write high quality code is extremely important in software development. Quality code decreases time spent trying to understand it, making the code easier to maintain and reducing the possibility of bugs. I thought this blog was very well done because it was entertaining to read and gave plenty of examples. Reading this blog helped cement ideas that I learned previously from this class and taught me new techniques that increase code quality. Since none of the information is hard to understand I can begin applying what I’ve learned right now, and hopefully I will continue to get better at writing clean code.

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

Common Code Smells

https://8thlight.com/blog/georgina-mcfadyen/2017/01/19/common-code-smells.html

This blog describes some of the most common code smells. A code smell is “a surface indication that usually corresponds to a deeper problem in the system.” Being able to catch code smells early will make it easier to refactor into code that is more extendable, readable, and supportable.

Long Methods

Having long methods makes your code harder to maintain and debug. It will also be more difficult to read as you have to keep a lot of complex logic in mind while reading a long method. Ideally, a method should not have more than one responsibility.

Refuse Bequest

Inheritance is not always the best model to use. If inherited methods go unused or are overridden to do nothing, it could be a sign of this code smell. Inheritance should only be used when a class needs to reuse code from its superclass.

Data Clumps

If multiple methods take the same type of parameters, it’s a sign that those parameters are probably related. The parameters can be combined together in a class to keep them together, which will help keep the code organized.

For example, instead of having a method with three parameters:

connect(String host, int port, String username);

They can be combined in a class so that a reference to the class object is all that has to be passed into the parameter list:

class DatabaseCredentials{
 ...
   public String getHost(){
     return host;
   }
   public int getPort(){
     return port;
   }
   public String getUsername(){
     return username;
   }
}
...
connect(DatabaseCredentials databaseCredentials);

Duplicate Code

This is the same idea as the Don’t Repeat Yourself design principle. Duplicate code is unnecessary and will create similar bugs in different parts of code.

Middle Man

If a class exists just to delegate to another class, you should ask yourself if it is really necessary. If a class doesn’t justify its existence, it should be removed.

Primitive Obsession

Primitive types give little domain context and are not always clear. Where primitives have a domain meaning, it is a good idea to wrap them in a small class to represent the idea.

Comments

Comments provide little value when they reiterate what can be read by a developer, especially if they have not been updated and no longer reflect the current code. Before adding a comment to clarify a piece of code, try to refactor the code so that the comment is no longer needed.

I chose this blog post because code smells are another topic on the concept map. They are similar to design principles and anti-patterns because being aware of them will make sure that good coding practices are being followed. Like the design principles and anti-patterns, I will be applying what I’ve learned to my future code. The more of these blogs I read the better understanding I have of how object-oriented code should be structured, which is one of the important learning outcomes of this class.

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

10 Object Oriented Design Principles

http://javarevisited.blogspot.com/2012/03/10-object-oriented-design-principles.html

For my blog post this week I chose another topic on the concept map that I thought looked interesting: design principles. These are helpful guidelines to follow that will make your code cleaner and more modular. This blog post describes 10 design principles that are useful in object oriented programming.

  1. DRY (Don’t Repeat Yourself) – Means don’t write duplicate code. It is better to abstract common things in one place as this will make your code easier to maintain.
  2. Encapsulate What Changes –  This will make it easier to modify your code in the future. One good way to implement this is by making variables and methods private by default and increasing access step by step.
  3. Open/Closed Principle – Classes and methods should be open for extension and closed for modification. Following this principle means that you will not have to change much existing code when new functionality is added.
  4. Single Responsibility Principle – A class should always handle a single functionality. Introducing more functionality to a class will increase coupling which makes it hard to modify a portion of code without breaking another part.
  5. Dependency Injection or Inversion Principle – High level modules should not depend on low-level modules; both should depend on abstractions.
  6. Favor Composition Over Inheritance – Composition is a lot more flexible than inheritance and allows changes to the behavior of a class at run-time.
  7. Liskov Substitution Principle – Subtypes should be able to be substituted for their supertypes without any issues. To follow this principle, subclasses must enhance functionality and not reduce it.
  8.  Interface Segregation Principle (ISP) – Avoid monolithic interfaces that have multiple functionalities. This is intended to keep a system decoupled which makes it easier to change.
  9. Program For an Interface, Not an Implementation – Leads to flexible code that can work with any new implementation of an interface.
  10. Delegation Principle – Delegate tasks to specific classes. An example of this design principle is the equals() method in Java.

I chose this blog because I wanted to learn more about design principles. We have covered some of them in class, such as the open/closed principle and composition over inheritance. However, this blog introduced me to a few new ones like the Liskov Substitution principle and interface segregation principle. I thought this was a decent rundown of the most common design principles, but I could tell the author is not a native English speaker which made some parts not entirely clear. This encouraged me to look up other resources and now I feel like I have a firm grasp on all of these principles. I will be applying what I’ve learned to all future code I write because like the design patterns, they will make my code more flexible, readable, and easy to maintain.

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